2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <sys/ioctl.h>
27 #include <sys/resource.h>
33 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
35 #include <cutils/compiler.h>
36 #include <cutils/log.h>
37 #include <cutils/properties.h>
38 #include <hardware/gralloc.h>
39 #include <hardware/hardware.h>
40 #include <hardware/hwcomposer.h>
41 #include <hardware_legacy/uevent.h>
42 #include <utils/String8.h>
43 #include <utils/Vector.h>
45 #include <sync/sync.h>
48 #include "gralloc_priv.h"
49 #include "exynos_gscaler.h"
50 #include "exynos_format.h"
51 #include "exynos_v4l2.h"
52 #include "s5p_tvout_v4l2.h"
54 const size_t NUM_HW_WINDOWS
= 5;
55 const size_t NO_FB_NEEDED
= NUM_HW_WINDOWS
+ 1;
56 const size_t MAX_PIXELS
= 2560 * 1600 * 2;
57 const size_t GSC_W_ALIGNMENT
= 16;
58 const size_t GSC_H_ALIGNMENT
= 16;
59 const size_t GSC_DST_CROP_W_ALIGNMENT_RGB888
= 32;
60 const size_t GSC_DST_W_ALIGNMENT_RGB888
= 32;
61 const size_t GSC_DST_H_ALIGNMENT_RGB888
= 1;
62 const size_t FIMD_GSC_IDX
= 0;
63 const size_t HDMI_GSC_IDX
= 1;
64 const int AVAILABLE_GSC_UNITS
[] = { 0, 3 };
65 const size_t NUM_GSC_UNITS
= sizeof(AVAILABLE_GSC_UNITS
) /
66 sizeof(AVAILABLE_GSC_UNITS
[0]);
67 const size_t BURSTLEN_BYTES
= 16 * 8;
68 const size_t NUM_HDMI_BUFFERS
= 3;
70 struct exynos5_hwc_composer_device_1_t
;
72 struct exynos5_gsc_map_t
{
76 // TODO: GSC_LOCAL_PATH
81 struct exynos5_hwc_post_data_t
{
82 int overlay_map
[NUM_HW_WINDOWS
];
83 exynos5_gsc_map_t gsc_map
[NUM_HW_WINDOWS
];
87 const size_t NUM_GSC_DST_BUFS
= 3;
88 struct exynos5_gsc_data_t
{
90 exynos_gsc_img src_cfg
;
91 exynos_gsc_img dst_cfg
;
92 buffer_handle_t dst_buf
[NUM_GSC_DST_BUFS
];
93 int dst_buf_fence
[NUM_GSC_DST_BUFS
];
108 struct exynos5_hwc_composer_device_1_t
{
109 hwc_composer_device_1_t base
;
113 exynos5_hwc_post_data_t bufs
;
115 const private_module_t
*gralloc_module
;
116 alloc_device_t
*alloc_device
;
117 const hwc_procs_t
*procs
;
118 pthread_t vsync_thread
;
125 int32_t vsync_period
;
135 hdmi_layer_t hdmi_layers
[2];
137 exynos5_gsc_data_t gsc
[NUM_GSC_UNITS
];
139 struct s3c_fb_win_config last_config
[NUM_HW_WINDOWS
];
140 size_t last_fb_window
;
141 const void *last_handles
[NUM_HW_WINDOWS
];
142 exynos5_gsc_map_t last_gsc_map
[NUM_HW_WINDOWS
];
145 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
148 static void dump_handle(private_handle_t
*h
)
150 ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
151 h
->format
, h
->width
, h
->height
, h
->stride
, h
->vstride
);
154 static void dump_layer(hwc_layer_1_t
const *l
)
156 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
157 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
158 l
->compositionType
, l
->flags
, l
->handle
, l
->transform
,
163 l
->sourceCrop
.bottom
,
164 l
->displayFrame
.left
,
166 l
->displayFrame
.right
,
167 l
->displayFrame
.bottom
);
169 if(l
->handle
&& !(l
->flags
& HWC_SKIP_LAYER
))
170 dump_handle(private_handle_t::dynamicCast(l
->handle
));
173 static void dump_config(s3c_fb_win_config
&c
)
175 ALOGV("\tstate = %u", c
.state
);
176 if (c
.state
== c
.S3C_FB_WIN_STATE_BUFFER
) {
177 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
178 "x = %d, y = %d, w = %u, h = %u, "
179 "format = %u, blending = %u",
180 c
.fd
, c
.offset
, c
.stride
,
182 c
.format
, c
.blending
);
184 else if (c
.state
== c
.S3C_FB_WIN_STATE_COLOR
) {
185 ALOGV("\t\tcolor = %u", c
.color
);
189 static void dump_gsc_img(exynos_gsc_img
&c
)
191 ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
192 c
.x
, c
.y
, c
.w
, c
.h
, c
.fw
, c
.fh
);
193 ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
194 c
.yaddr
, c
.uaddr
, c
.vaddr
, c
.rot
, c
.cacheable
, c
.drmMode
);
197 inline int WIDTH(const hwc_rect
&rect
) { return rect
.right
- rect
.left
; }
198 inline int HEIGHT(const hwc_rect
&rect
) { return rect
.bottom
- rect
.top
; }
199 template<typename T
> inline T
max(T a
, T b
) { return (a
> b
) ? a
: b
; }
200 template<typename T
> inline T
min(T a
, T b
) { return (a
< b
) ? a
: b
; }
202 static int dup_or_warn(int fence
)
204 int dup_fd
= dup(fence
);
206 ALOGW("fence dup failed: %s", strerror(errno
));
210 static int merge_or_warn(const char *name
, int f1
, int f2
)
212 int merge_fd
= sync_merge(name
, f1
, f2
);
214 ALOGW("fence merge failed: %s", strerror(errno
));
218 template<typename T
> void align_crop_and_center(T
&w
, T
&h
,
219 hwc_rect_t
*crop
, size_t alignment
)
221 double aspect
= 1.0 * h
/ w
;
222 T w_orig
= w
, h_orig
= h
;
224 w
= ALIGN(w
, alignment
);
225 h
= round(aspect
* w
);
227 crop
->left
= (w
- w_orig
) / 2;
228 crop
->top
= (h
- h_orig
) / 2;
229 crop
->right
= crop
->left
+ w_orig
;
230 crop
->bottom
= crop
->top
+ h_orig
;
234 static bool is_transformed(const hwc_layer_1_t
&layer
)
236 return layer
.transform
!= 0;
239 static bool is_rotated(const hwc_layer_1_t
&layer
)
241 return (layer
.transform
& HAL_TRANSFORM_ROT_90
) ||
242 (layer
.transform
& HAL_TRANSFORM_ROT_180
);
245 static bool is_scaled(const hwc_layer_1_t
&layer
)
247 return WIDTH(layer
.displayFrame
) != WIDTH(layer
.sourceCrop
) ||
248 HEIGHT(layer
.displayFrame
) != HEIGHT(layer
.sourceCrop
);
251 static inline bool gsc_dst_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
253 return c1
.x
!= c2
.x
||
257 c1
.format
!= c2
.format
||
259 c1
.cacheable
!= c2
.cacheable
||
260 c1
.drmMode
!= c2
.drmMode
;
263 static inline bool gsc_src_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
265 return gsc_dst_cfg_changed(c1
, c2
) ||
270 static enum s3c_fb_pixel_format
exynos5_format_to_s3c_format(int format
)
273 case HAL_PIXEL_FORMAT_RGBA_8888
:
274 return S3C_FB_PIXEL_FORMAT_RGBA_8888
;
275 case HAL_PIXEL_FORMAT_RGBX_8888
:
276 return S3C_FB_PIXEL_FORMAT_RGBX_8888
;
277 case HAL_PIXEL_FORMAT_RGBA_5551
:
278 return S3C_FB_PIXEL_FORMAT_RGBA_5551
;
279 case HAL_PIXEL_FORMAT_RGB_565
:
280 return S3C_FB_PIXEL_FORMAT_RGB_565
;
281 case HAL_PIXEL_FORMAT_BGRA_8888
:
282 return S3C_FB_PIXEL_FORMAT_BGRA_8888
;
284 return S3C_FB_PIXEL_FORMAT_MAX
;
288 static bool exynos5_format_is_supported(int format
)
290 return exynos5_format_to_s3c_format(format
) < S3C_FB_PIXEL_FORMAT_MAX
;
293 static bool exynos5_format_is_rgb(int format
)
296 case HAL_PIXEL_FORMAT_RGBA_8888
:
297 case HAL_PIXEL_FORMAT_RGBX_8888
:
298 case HAL_PIXEL_FORMAT_RGB_888
:
299 case HAL_PIXEL_FORMAT_RGB_565
:
300 case HAL_PIXEL_FORMAT_BGRA_8888
:
301 case HAL_PIXEL_FORMAT_RGBA_5551
:
302 case HAL_PIXEL_FORMAT_RGBA_4444
:
310 static bool exynos5_format_is_supported_by_gscaler(int format
)
313 case HAL_PIXEL_FORMAT_RGBX_8888
:
314 case HAL_PIXEL_FORMAT_RGB_565
:
315 case HAL_PIXEL_FORMAT_EXYNOS_YV12
:
316 case HAL_PIXEL_FORMAT_YCbCr_420_SP
:
317 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED
:
325 static bool exynos5_format_is_ycrcb(int format
)
327 return format
== HAL_PIXEL_FORMAT_EXYNOS_YV12
;
330 static bool exynos5_format_requires_gscaler(int format
)
332 return (exynos5_format_is_supported_by_gscaler(format
) &&
333 (format
!= HAL_PIXEL_FORMAT_RGBX_8888
) && (format
!= HAL_PIXEL_FORMAT_RGB_565
));
336 static uint8_t exynos5_format_to_bpp(int format
)
339 case HAL_PIXEL_FORMAT_RGBA_8888
:
340 case HAL_PIXEL_FORMAT_RGBX_8888
:
341 case HAL_PIXEL_FORMAT_BGRA_8888
:
344 case HAL_PIXEL_FORMAT_RGBA_5551
:
345 case HAL_PIXEL_FORMAT_RGBA_4444
:
346 case HAL_PIXEL_FORMAT_RGB_565
:
350 ALOGW("unrecognized pixel format %u", format
);
355 static bool is_x_aligned(const hwc_layer_1_t
&layer
, int format
)
357 if (!exynos5_format_is_supported(format
))
360 uint8_t bpp
= exynos5_format_to_bpp(format
);
361 uint8_t pixel_alignment
= 32 / bpp
;
363 return (layer
.displayFrame
.left
% pixel_alignment
) == 0 &&
364 (layer
.displayFrame
.right
% pixel_alignment
) == 0;
367 static bool dst_crop_w_aligned(int dest_w
)
369 int dst_crop_w_alignement
;
371 /* GSC's dst crop size should be aligned 128Bytes */
372 dst_crop_w_alignement
= GSC_DST_CROP_W_ALIGNMENT_RGB888
;
374 return (dest_w
% dst_crop_w_alignement
) == 0;
377 static bool exynos5_supports_gscaler(hwc_layer_1_t
&layer
, int format
,
380 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
382 int max_w
= is_rotated(layer
) ? 2048 : 4800;
383 int max_h
= is_rotated(layer
) ? 2048 : 3344;
385 bool rot90or270
= !!(layer
.transform
& HAL_TRANSFORM_ROT_90
);
386 // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
387 // HAL_TRANSFORM_ROT_180
389 int src_w
= WIDTH(layer
.sourceCrop
), src_h
= HEIGHT(layer
.sourceCrop
);
392 dest_w
= HEIGHT(layer
.displayFrame
);
393 dest_h
= WIDTH(layer
.displayFrame
);
395 dest_w
= WIDTH(layer
.displayFrame
);
396 dest_h
= HEIGHT(layer
.displayFrame
);
399 if (handle
->flags
& GRALLOC_USAGE_PROTECTED
)
400 align_crop_and_center(dest_w
, dest_h
, NULL
,
401 GSC_DST_CROP_W_ALIGNMENT_RGB888
);
403 int max_downscale
= local_path
? 4 : 16;
404 const int max_upscale
= 8;
406 return exynos5_format_is_supported_by_gscaler(format
) &&
407 dst_crop_w_aligned(dest_w
) &&
408 handle
->stride
<= max_w
&&
409 handle
->stride
% GSC_W_ALIGNMENT
== 0 &&
410 src_w
<= dest_w
* max_downscale
&&
411 dest_w
<= src_w
* max_upscale
&&
412 handle
->vstride
<= max_h
&&
413 handle
->vstride
% GSC_H_ALIGNMENT
== 0 &&
414 src_h
<= dest_h
* max_downscale
&&
415 dest_h
<= src_h
* max_upscale
&&
417 (!rot90or270
|| layer
.sourceCrop
.top
% 2 == 0) &&
418 (!rot90or270
|| layer
.sourceCrop
.left
% 2 == 0);
422 static bool exynos5_requires_gscaler(hwc_layer_1_t
&layer
, int format
)
424 return exynos5_format_requires_gscaler(format
) || is_scaled(layer
)
425 || is_transformed(layer
) || !is_x_aligned(layer
, format
);
428 int hdmi_get_config(struct exynos5_hwc_composer_device_1_t
*dev
)
430 struct v4l2_dv_preset preset
;
431 struct v4l2_dv_enum_preset enum_preset
;
436 if (ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_G_DV_PRESET
, &preset
) < 0) {
437 ALOGE("%s: g_dv_preset error, %d", __func__
, errno
);
442 enum_preset
.index
= index
++;
443 ret
= ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_ENUM_DV_PRESETS
, &enum_preset
);
448 ALOGE("%s: enum_dv_presets error, %d", __func__
, errno
);
452 ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
453 __func__
, enum_preset
.index
, enum_preset
.preset
,
454 enum_preset
.width
, enum_preset
.height
, enum_preset
.name
);
456 if (preset
.preset
== enum_preset
.preset
) {
457 dev
->hdmi_w
= enum_preset
.width
;
458 dev
->hdmi_h
= enum_preset
.height
;
463 return found
? 0 : -1;
466 static enum s3c_fb_blending
exynos5_blending_to_s3c_blending(int32_t blending
)
469 case HWC_BLENDING_NONE
:
470 return S3C_FB_BLENDING_NONE
;
471 case HWC_BLENDING_PREMULT
:
472 return S3C_FB_BLENDING_PREMULT
;
473 case HWC_BLENDING_COVERAGE
:
474 return S3C_FB_BLENDING_COVERAGE
;
477 return S3C_FB_BLENDING_MAX
;
481 static bool exynos5_blending_is_supported(int32_t blending
)
483 return exynos5_blending_to_s3c_blending(blending
) < S3C_FB_BLENDING_MAX
;
487 static int hdmi_enable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
493 struct v4l2_requestbuffers reqbuf
;
494 memset(&reqbuf
, 0, sizeof(reqbuf
));
495 reqbuf
.count
= NUM_HDMI_BUFFERS
;
496 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
497 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
498 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0) {
499 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
503 if (reqbuf
.count
!= NUM_HDMI_BUFFERS
) {
504 ALOGE("%s: layer%d: didn't get buffer", __func__
, hl
.id
);
509 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_PIXEL_BLEND_ENABLE
, 1) < 0) {
510 ALOGE("%s: layer%d: PIXEL_BLEND_ENABLE failed %d", __func__
,
516 ALOGV("%s: layer%d enabled", __func__
, hl
.id
);
521 static void hdmi_disable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
528 if (exynos_v4l2_streamoff(hl
.fd
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) < 0)
529 ALOGE("%s: layer%d: streamoff failed %d", __func__
, hl
.id
, errno
);
530 hl
.streaming
= false;
533 struct v4l2_requestbuffers reqbuf
;
534 memset(&reqbuf
, 0, sizeof(reqbuf
));
535 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
536 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
537 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0)
538 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
540 memset(&hl
.cfg
, 0, sizeof(hl
.cfg
));
545 ALOGV("%s: layer%d disabled", __func__
, hl
.id
);
548 static void hdmi_hide_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
551 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_LAYER_PRIO
, 0) < 0)
552 ALOGE("%s: layer%d: LAYER_PRIO failed %d", __func__
,
556 static void hdmi_show_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
559 int prio
= hl
.id
? 3 : 2;
561 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_LAYER_PRIO
, prio
) < 0)
562 ALOGE("%s: layer%d: LAYER_PRIO failed %d", __func__
,
566 static int hdmi_enable(struct exynos5_hwc_composer_device_1_t
*dev
)
568 /* hdmi not supported */
569 if (dev
->hdmi_mixer0
< 0)
572 if (dev
->hdmi_enabled
)
575 if (dev
->hdmi_blanked
)
578 struct v4l2_subdev_format sd_fmt
;
579 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
580 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
581 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
582 sd_fmt
.format
.width
= dev
->hdmi_w
;
583 sd_fmt
.format
.height
= dev
->hdmi_h
;
584 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
585 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
586 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
590 struct v4l2_subdev_crop sd_crop
;
591 memset(&sd_crop
, 0, sizeof(sd_crop
));
592 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
593 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
594 sd_crop
.rect
.width
= dev
->hdmi_w
;
595 sd_crop
.rect
.height
= dev
->hdmi_h
;
596 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
597 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
601 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
602 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
603 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
604 sd_fmt
.format
.width
= dev
->hdmi_w
;
605 sd_fmt
.format
.height
= dev
->hdmi_h
;
606 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
607 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
608 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
612 memset(&sd_crop
, 0, sizeof(sd_crop
));
613 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
614 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
615 sd_crop
.rect
.width
= dev
->hdmi_w
;
616 sd_crop
.rect
.height
= dev
->hdmi_h
;
617 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
618 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
622 char value
[PROPERTY_VALUE_MAX
];
623 property_get("persist.hdmi.hdcp_enabled", value
, "1");
624 int hdcp_enabled
= atoi(value
);
626 if (exynos_v4l2_s_ctrl(dev
->hdmi_layers
[1].fd
, V4L2_CID_TV_HDCP_ENABLE
,
628 ALOGE("%s: s_ctrl(CID_TV_HDCP_ENABLE) failed %d", __func__
, errno
);
630 /* "3" is RGB709_16_235 */
631 property_get("persist.hdmi.color_range", value
, "3");
632 int color_range
= atoi(value
);
634 if (exynos_v4l2_s_ctrl(dev
->hdmi_layers
[1].fd
, V4L2_CID_TV_SET_COLOR_RANGE
,
636 ALOGE("%s: s_ctrl(CID_TV_COLOR_RANGE) failed %d", __func__
, errno
);
638 hdmi_enable_layer(dev
, dev
->hdmi_layers
[1]);
640 dev
->hdmi_enabled
= true;
644 static void hdmi_disable(struct exynos5_hwc_composer_device_1_t
*dev
)
646 if (!dev
->hdmi_enabled
)
649 hdmi_disable_layer(dev
, dev
->hdmi_layers
[0]);
650 hdmi_disable_layer(dev
, dev
->hdmi_layers
[1]);
652 exynos5_cleanup_gsc_m2m(dev
, HDMI_GSC_IDX
);
653 dev
->hdmi_enabled
= false;
656 static int hdmi_output(struct exynos5_hwc_composer_device_1_t
*dev
,
658 hwc_layer_1_t
&layer
,
666 memset(&cfg
, 0, sizeof(cfg
));
667 cfg
.x
= layer
.displayFrame
.left
;
668 cfg
.y
= layer
.displayFrame
.top
;
669 cfg
.w
= WIDTH(layer
.displayFrame
);
670 cfg
.h
= HEIGHT(layer
.displayFrame
);
672 if (gsc_src_cfg_changed(hl
.cfg
, cfg
)) {
673 hdmi_disable_layer(dev
, hl
);
675 struct v4l2_format fmt
;
676 memset(&fmt
, 0, sizeof(fmt
));
677 fmt
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
678 fmt
.fmt
.pix_mp
.width
= h
->stride
;
679 fmt
.fmt
.pix_mp
.height
= cfg
.h
;
680 fmt
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_BGR32
;
681 fmt
.fmt
.pix_mp
.field
= V4L2_FIELD_ANY
;
682 fmt
.fmt
.pix_mp
.num_planes
= 1;
683 ret
= exynos_v4l2_s_fmt(hl
.fd
, &fmt
);
685 ALOGE("%s: layer%d: s_fmt failed %d", __func__
, hl
.id
, errno
);
689 struct v4l2_subdev_crop sd_crop
;
690 memset(&sd_crop
, 0, sizeof(sd_crop
));
692 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
694 sd_crop
.pad
= MIXER_G1_SUBDEV_PAD_SOURCE
;
695 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
696 sd_crop
.rect
.left
= cfg
.x
;
697 sd_crop
.rect
.top
= cfg
.y
;
698 sd_crop
.rect
.width
= cfg
.w
;
699 sd_crop
.rect
.height
= cfg
.h
;
700 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
701 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
705 hdmi_enable_layer(dev
, hl
);
707 ALOGV("HDMI layer%d configuration:", hl
.id
);
712 struct v4l2_buffer buffer
;
713 struct v4l2_plane planes
[1];
715 if (hl
.queued_buf
== NUM_HDMI_BUFFERS
) {
716 memset(&buffer
, 0, sizeof(buffer
));
717 memset(planes
, 0, sizeof(planes
));
718 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
719 buffer
.memory
= V4L2_MEMORY_DMABUF
;
721 buffer
.m
.planes
= planes
;
722 ret
= exynos_v4l2_dqbuf(hl
.fd
, &buffer
);
724 ALOGE("%s: layer%d: dqbuf failed %d", __func__
, hl
.id
, errno
);
730 memset(&buffer
, 0, sizeof(buffer
));
731 memset(planes
, 0, sizeof(planes
));
732 buffer
.index
= hl
.current_buf
;
733 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
734 buffer
.memory
= V4L2_MEMORY_DMABUF
;
735 buffer
.flags
= V4L2_BUF_FLAG_USE_SYNC
;
736 buffer
.reserved
= acquireFenceFd
;
738 buffer
.m
.planes
= planes
;
739 buffer
.m
.planes
[0].m
.fd
= h
->fd
;
740 if (exynos_v4l2_qbuf(hl
.fd
, &buffer
) < 0) {
741 ALOGE("%s: layer%d: qbuf failed %d", __func__
, hl
.id
, errno
);
747 *releaseFenceFd
= buffer
.reserved
;
749 close(buffer
.reserved
);
752 hl
.current_buf
= (hl
.current_buf
+ 1) % NUM_HDMI_BUFFERS
;
755 if (exynos_v4l2_streamon(hl
.fd
, buffer
.type
) < 0) {
756 ALOGE("%s: layer%d: streamon failed %d", __func__
, hl
.id
, errno
);
764 if (acquireFenceFd
>= 0)
765 close(acquireFenceFd
);
770 bool exynos5_is_offscreen(hwc_layer_1_t
&layer
,
771 struct exynos5_hwc_composer_device_1_t
*pdev
)
773 return layer
.displayFrame
.left
> pdev
->xres
||
774 layer
.displayFrame
.right
< 0 ||
775 layer
.displayFrame
.top
> pdev
->yres
||
776 layer
.displayFrame
.bottom
< 0;
779 size_t exynos5_visible_width(hwc_layer_1_t
&layer
, int format
,
780 struct exynos5_hwc_composer_device_1_t
*pdev
)
783 if (exynos5_requires_gscaler(layer
, format
))
786 bpp
= exynos5_format_to_bpp(format
);
787 int left
= max(layer
.displayFrame
.left
, 0);
788 int right
= min(layer
.displayFrame
.right
, pdev
->xres
);
790 return (right
- left
) * bpp
/ 8;
793 bool exynos5_supports_overlay(hwc_layer_1_t
&layer
, size_t i
,
794 struct exynos5_hwc_composer_device_1_t
*pdev
)
796 if (layer
.flags
& HWC_SKIP_LAYER
) {
797 ALOGV("\tlayer %u: skipping", i
);
801 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
804 ALOGV("\tlayer %u: handle is NULL", i
);
808 if (exynos5_visible_width(layer
, handle
->format
, pdev
) < BURSTLEN_BYTES
) {
809 ALOGV("\tlayer %u: visible area is too narrow", i
);
812 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
813 if (!exynos5_supports_gscaler(layer
, handle
->format
, false)) {
814 ALOGV("\tlayer %u: gscaler required but not supported", i
);
818 if (!exynos5_format_is_supported(handle
->format
)) {
819 ALOGV("\tlayer %u: pixel format %u not supported", i
, handle
->format
);
823 if (!exynos5_blending_is_supported(layer
.blending
)) {
824 ALOGV("\tlayer %u: blending %d not supported", i
, layer
.blending
);
827 if (CC_UNLIKELY(exynos5_is_offscreen(layer
, pdev
))) {
828 ALOGW("\tlayer %u: off-screen", i
);
835 inline bool intersect(const hwc_rect
&r1
, const hwc_rect
&r2
)
837 return !(r1
.left
> r2
.right
||
838 r1
.right
< r2
.left
||
839 r1
.top
> r2
.bottom
||
843 inline hwc_rect
intersection(const hwc_rect
&r1
, const hwc_rect
&r2
)
846 i
.top
= max(r1
.top
, r2
.top
);
847 i
.bottom
= min(r1
.bottom
, r2
.bottom
);
848 i
.left
= max(r1
.left
, r2
.left
);
849 i
.right
= min(r1
.right
, r2
.right
);
853 static int exynos5_prepare_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
854 hwc_display_contents_1_t
* contents
)
856 ALOGV("preparing %u layers for FIMD", contents
->numHwLayers
);
858 memset(pdev
->bufs
.gsc_map
, 0, sizeof(pdev
->bufs
.gsc_map
));
860 bool force_fb
= pdev
->force_gpu
;
861 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
862 pdev
->bufs
.overlay_map
[i
] = -1;
864 bool fb_needed
= false;
865 size_t first_fb
= 0, last_fb
= 0;
867 // find unsupported overlays
868 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
869 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
871 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
872 ALOGV("\tlayer %u: framebuffer target", i
);
876 if (layer
.compositionType
== HWC_BACKGROUND
&& !force_fb
) {
877 ALOGV("\tlayer %u: background supported", i
);
878 dump_layer(&contents
->hwLayers
[i
]);
882 if (exynos5_supports_overlay(contents
->hwLayers
[i
], i
, pdev
) &&
884 ALOGV("\tlayer %u: overlay supported", i
);
885 layer
.compositionType
= HWC_OVERLAY
;
886 dump_layer(&contents
->hwLayers
[i
]);
895 layer
.compositionType
= HWC_FRAMEBUFFER
;
897 dump_layer(&contents
->hwLayers
[i
]);
900 // can't composite overlays sandwiched between framebuffers
902 for (size_t i
= first_fb
; i
< last_fb
; i
++)
903 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
905 // Incrementally try to add our supported layers to hardware windows.
906 // If adding a layer would violate a hardware constraint, force it
907 // into the framebuffer and try again. (Revisiting the entire list is
908 // necessary because adding a layer to the framebuffer can cause other
909 // windows to retroactively violate constraints.)
913 android::Vector
<hwc_rect
> rects
;
914 android::Vector
<hwc_rect
> overlaps
;
915 size_t pixels_left
, windows_left
;
921 fb_rect
.top
= fb_rect
.left
= 0;
922 fb_rect
.right
= pdev
->xres
- 1;
923 fb_rect
.bottom
= pdev
->yres
- 1;
924 pixels_left
= MAX_PIXELS
- pdev
->xres
* pdev
->yres
;
925 windows_left
= NUM_HW_WINDOWS
- 1;
926 rects
.push_back(fb_rect
);
929 pixels_left
= MAX_PIXELS
;
930 windows_left
= NUM_HW_WINDOWS
;
935 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
936 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
937 if ((layer
.flags
& HWC_SKIP_LAYER
) ||
938 layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
)
941 private_handle_t
*handle
= private_handle_t::dynamicCast(
944 // we've already accounted for the framebuffer above
945 if (layer
.compositionType
== HWC_FRAMEBUFFER
)
948 // only layer 0 can be HWC_BACKGROUND, so we can
949 // unconditionally allow it without extra checks
950 if (layer
.compositionType
== HWC_BACKGROUND
) {
955 size_t pixels_needed
= WIDTH(layer
.displayFrame
) *
956 HEIGHT(layer
.displayFrame
);
957 bool can_compose
= windows_left
&& pixels_needed
<= pixels_left
;
958 bool gsc_required
= exynos5_requires_gscaler(layer
, handle
->format
);
960 can_compose
= can_compose
&& !gsc_used
;
962 // hwc_rect_t right and bottom values are normally exclusive;
963 // the intersection logic is simpler if we make them inclusive
964 hwc_rect_t visible_rect
= layer
.displayFrame
;
965 visible_rect
.right
--; visible_rect
.bottom
--;
967 // no more than 2 layers can overlap on a given pixel
968 for (size_t j
= 0; can_compose
&& j
< overlaps
.size(); j
++) {
969 if (intersect(visible_rect
, overlaps
.itemAt(j
)))
974 layer
.compositionType
= HWC_FRAMEBUFFER
;
976 first_fb
= last_fb
= i
;
980 first_fb
= min(i
, first_fb
);
981 last_fb
= max(i
, last_fb
);
987 for (size_t j
= 0; j
< rects
.size(); j
++) {
988 const hwc_rect_t
&other_rect
= rects
.itemAt(j
);
989 if (intersect(visible_rect
, other_rect
))
990 overlaps
.push_back(intersection(visible_rect
, other_rect
));
992 rects
.push_back(visible_rect
);
993 pixels_left
-= pixels_needed
;
1000 for (size_t i
= first_fb
; i
< last_fb
; i
++)
1001 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
1004 unsigned int nextWindow
= 0;
1006 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1007 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1009 if (fb_needed
&& i
== first_fb
) {
1010 ALOGV("assigning framebuffer to window %u\n",
1016 if (layer
.compositionType
!= HWC_FRAMEBUFFER
&&
1017 layer
.compositionType
!= HWC_FRAMEBUFFER_TARGET
) {
1018 ALOGV("assigning layer %u to window %u", i
, nextWindow
);
1019 pdev
->bufs
.overlay_map
[nextWindow
] = i
;
1020 if (layer
.compositionType
== HWC_OVERLAY
) {
1021 private_handle_t
*handle
=
1022 private_handle_t::dynamicCast(layer
.handle
);
1023 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
1024 ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS
[FIMD_GSC_IDX
]);
1025 pdev
->bufs
.gsc_map
[nextWindow
].mode
=
1026 exynos5_gsc_map_t::GSC_M2M
;
1027 pdev
->bufs
.gsc_map
[nextWindow
].idx
= FIMD_GSC_IDX
;
1035 exynos5_cleanup_gsc_m2m(pdev
, FIMD_GSC_IDX
);
1038 pdev
->bufs
.fb_window
= first_fb
;
1040 pdev
->bufs
.fb_window
= NO_FB_NEEDED
;
1045 static int exynos5_prepare_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1046 hwc_display_contents_1_t
* contents
)
1048 ALOGV("preparing %u layers for HDMI", contents
->numHwLayers
);
1049 hwc_layer_1_t
*video_layer
= NULL
;
1051 pdev
->hdmi_fb_needed
= false;
1053 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1054 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1056 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1057 ALOGV("\tlayer %u: framebuffer target", i
);
1061 if (layer
.compositionType
== HWC_BACKGROUND
) {
1062 ALOGV("\tlayer %u: background layer", i
);
1068 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1069 if (h
->flags
& GRALLOC_USAGE_PROTECTED
) {
1071 video_layer
= &layer
;
1072 layer
.compositionType
= HWC_OVERLAY
;
1073 ALOGV("\tlayer %u: video layer", i
);
1080 pdev
->hdmi_fb_needed
= true;
1081 layer
.compositionType
= HWC_FRAMEBUFFER
;
1088 static int exynos5_prepare(hwc_composer_device_1_t
*dev
,
1089 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1091 if (!numDisplays
|| !displays
)
1094 exynos5_hwc_composer_device_1_t
*pdev
=
1095 (exynos5_hwc_composer_device_1_t
*)dev
;
1096 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1097 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1099 if (pdev
->hdmi_hpd
) {
1105 if (fimd_contents
) {
1106 int err
= exynos5_prepare_fimd(pdev
, fimd_contents
);
1111 if (hdmi_contents
) {
1112 int err
= exynos5_prepare_hdmi(pdev
, hdmi_contents
);
1120 static int exynos5_config_gsc_m2m(hwc_layer_1_t
&layer
,
1121 alloc_device_t
* alloc_device
, exynos5_gsc_data_t
*gsc_data
,
1122 int gsc_idx
, int dst_format
, hwc_rect_t
*sourceCrop
)
1124 ALOGV("configuring gscaler %u for memory-to-memory", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1126 private_handle_t
*src_handle
= private_handle_t::dynamicCast(layer
.handle
);
1127 buffer_handle_t dst_buf
;
1128 private_handle_t
*dst_handle
;
1131 exynos_gsc_img src_cfg
, dst_cfg
;
1132 memset(&src_cfg
, 0, sizeof(src_cfg
));
1133 memset(&dst_cfg
, 0, sizeof(dst_cfg
));
1135 hwc_rect_t sourceCropTemp
;
1137 sourceCrop
= &sourceCropTemp
;
1139 src_cfg
.x
= layer
.sourceCrop
.left
;
1140 src_cfg
.y
= layer
.sourceCrop
.top
;
1141 src_cfg
.w
= WIDTH(layer
.sourceCrop
);
1142 src_cfg
.fw
= src_handle
->stride
;
1143 src_cfg
.h
= HEIGHT(layer
.sourceCrop
);
1144 src_cfg
.fh
= src_handle
->vstride
;
1145 src_cfg
.yaddr
= src_handle
->fd
;
1146 if (exynos5_format_is_ycrcb(src_handle
->format
)) {
1147 src_cfg
.uaddr
= src_handle
->fd2
;
1148 src_cfg
.vaddr
= src_handle
->fd1
;
1150 src_cfg
.uaddr
= src_handle
->fd1
;
1151 src_cfg
.vaddr
= src_handle
->fd2
;
1153 src_cfg
.format
= src_handle
->format
;
1154 src_cfg
.drmMode
= !!(src_handle
->flags
& GRALLOC_USAGE_PROTECTED
);
1155 src_cfg
.acquireFenceFd
= layer
.acquireFenceFd
;
1156 layer
.acquireFenceFd
= -1;
1160 dst_cfg
.w
= WIDTH(layer
.displayFrame
);
1161 dst_cfg
.h
= HEIGHT(layer
.displayFrame
);
1162 dst_cfg
.rot
= layer
.transform
;
1163 dst_cfg
.drmMode
= src_cfg
.drmMode
;
1164 dst_cfg
.format
= dst_format
;
1165 dst_cfg
.narrowRgb
= !exynos5_format_is_rgb(src_handle
->format
);
1166 if (dst_cfg
.drmMode
)
1167 align_crop_and_center(dst_cfg
.w
, dst_cfg
.h
, sourceCrop
,
1168 GSC_DST_CROP_W_ALIGNMENT_RGB888
);
1170 ALOGV("source configuration:");
1171 dump_gsc_img(src_cfg
);
1173 bool reconfigure
= gsc_src_cfg_changed(src_cfg
, gsc_data
->src_cfg
) ||
1174 gsc_dst_cfg_changed(dst_cfg
, gsc_data
->dst_cfg
);
1177 int usage
= GRALLOC_USAGE_SW_READ_NEVER
|
1178 GRALLOC_USAGE_SW_WRITE_NEVER
|
1179 GRALLOC_USAGE_HW_COMPOSER
;
1181 if (src_handle
->flags
& GRALLOC_USAGE_PROTECTED
)
1182 usage
|= GRALLOC_USAGE_PROTECTED
;
1184 int w
= ALIGN(dst_cfg
.w
, GSC_DST_W_ALIGNMENT_RGB888
);
1185 int h
= ALIGN(dst_cfg
.h
, GSC_DST_H_ALIGNMENT_RGB888
);
1187 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1188 if (gsc_data
->dst_buf
[i
]) {
1189 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1190 gsc_data
->dst_buf
[i
] = NULL
;
1193 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1194 close(gsc_data
->dst_buf_fence
[i
]);
1195 gsc_data
->dst_buf_fence
[i
] = -1;
1198 int ret
= alloc_device
->alloc(alloc_device
, w
, h
,
1199 HAL_PIXEL_FORMAT_RGBX_8888
, usage
, &gsc_data
->dst_buf
[i
],
1202 ALOGE("failed to allocate destination buffer: %s",
1208 gsc_data
->current_buf
= 0;
1211 dst_buf
= gsc_data
->dst_buf
[gsc_data
->current_buf
];
1212 dst_handle
= private_handle_t::dynamicCast(dst_buf
);
1214 dst_cfg
.fw
= dst_handle
->stride
;
1215 dst_cfg
.fh
= dst_handle
->vstride
;
1216 dst_cfg
.yaddr
= dst_handle
->fd
;
1217 dst_cfg
.acquireFenceFd
= gsc_data
->dst_buf_fence
[gsc_data
->current_buf
];
1218 gsc_data
->dst_buf_fence
[gsc_data
->current_buf
] = -1;
1220 ALOGV("destination configuration:");
1221 dump_gsc_img(dst_cfg
);
1223 if ((int)dst_cfg
.w
!= WIDTH(layer
.displayFrame
))
1224 ALOGV("padding %u x %u output to %u x %u and cropping to {%u,%u,%u,%u}",
1225 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
),
1226 dst_cfg
.w
, dst_cfg
.h
, sourceCrop
->left
, sourceCrop
->top
,
1227 sourceCrop
->right
, sourceCrop
->bottom
);
1229 if (gsc_data
->gsc
) {
1230 ALOGV("reusing open gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1232 ALOGV("opening gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1233 gsc_data
->gsc
= exynos_gsc_create_exclusive(
1234 AVAILABLE_GSC_UNITS
[gsc_idx
], GSC_M2M_MODE
, GSC_DUMMY
, true);
1235 if (!gsc_data
->gsc
) {
1236 ALOGE("failed to create gscaler handle");
1243 ret
= exynos_gsc_stop_exclusive(gsc_data
->gsc
);
1245 ALOGE("failed to stop gscaler %u", gsc_idx
);
1246 goto err_gsc_config
;
1249 ret
= exynos_gsc_config_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1251 ALOGE("failed to configure gscaler %u", gsc_idx
);
1252 goto err_gsc_config
;
1256 ret
= exynos_gsc_run_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1258 ALOGE("failed to run gscaler %u", gsc_idx
);
1259 goto err_gsc_config
;
1262 gsc_data
->src_cfg
= src_cfg
;
1263 gsc_data
->dst_cfg
= dst_cfg
;
1265 layer
.releaseFenceFd
= src_cfg
.releaseFenceFd
;
1270 exynos_gsc_destroy(gsc_data
->gsc
);
1271 gsc_data
->gsc
= NULL
;
1273 if (src_cfg
.acquireFenceFd
>= 0)
1274 close(src_cfg
.acquireFenceFd
);
1275 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1276 if (gsc_data
->dst_buf
[i
]) {
1277 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1278 gsc_data
->dst_buf
[i
] = NULL
;
1280 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1281 close(gsc_data
->dst_buf_fence
[i
]);
1282 gsc_data
->dst_buf_fence
[i
] = -1;
1285 memset(&gsc_data
->src_cfg
, 0, sizeof(gsc_data
->src_cfg
));
1286 memset(&gsc_data
->dst_cfg
, 0, sizeof(gsc_data
->dst_cfg
));
1291 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
1294 exynos5_gsc_data_t
&gsc_data
= pdev
->gsc
[gsc_idx
];
1298 ALOGV("closing gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1300 exynos_gsc_stop_exclusive(gsc_data
.gsc
);
1301 exynos_gsc_destroy(gsc_data
.gsc
);
1302 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1303 if (gsc_data
.dst_buf
[i
])
1304 pdev
->alloc_device
->free(pdev
->alloc_device
, gsc_data
.dst_buf
[i
]);
1305 if (gsc_data
.dst_buf_fence
[i
] >= 0)
1306 close(gsc_data
.dst_buf_fence
[i
]);
1309 memset(&gsc_data
, 0, sizeof(gsc_data
));
1310 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++)
1311 gsc_data
.dst_buf_fence
[i
] = -1;
1314 static void exynos5_config_handle(private_handle_t
*handle
,
1315 hwc_rect_t
&sourceCrop
, hwc_rect_t
&displayFrame
,
1316 int32_t blending
, int fence_fd
, s3c_fb_win_config
&cfg
,
1317 exynos5_hwc_composer_device_1_t
*pdev
)
1320 uint32_t w
= WIDTH(displayFrame
);
1321 uint32_t h
= HEIGHT(displayFrame
);
1322 uint8_t bpp
= exynos5_format_to_bpp(handle
->format
);
1323 uint32_t offset
= (sourceCrop
.top
* handle
->stride
+ sourceCrop
.left
) * bpp
/ 8;
1325 if (displayFrame
.left
< 0) {
1326 unsigned int crop
= -displayFrame
.left
;
1327 ALOGV("layer off left side of screen; cropping %u pixels from left edge",
1331 offset
+= crop
* bpp
/ 8;
1333 x
= displayFrame
.left
;
1336 if (displayFrame
.right
> pdev
->xres
) {
1337 unsigned int crop
= displayFrame
.right
- pdev
->xres
;
1338 ALOGV("layer off right side of screen; cropping %u pixels from right edge",
1343 if (displayFrame
.top
< 0) {
1344 unsigned int crop
= -displayFrame
.top
;
1345 ALOGV("layer off top side of screen; cropping %u pixels from top edge",
1349 offset
+= handle
->stride
* crop
* bpp
/ 8;
1351 y
= displayFrame
.top
;
1354 if (displayFrame
.bottom
> pdev
->yres
) {
1355 int crop
= displayFrame
.bottom
- pdev
->yres
;
1356 ALOGV("layer off bottom side of screen; cropping %u pixels from bottom edge",
1361 cfg
.state
= cfg
.S3C_FB_WIN_STATE_BUFFER
;
1362 cfg
.fd
= handle
->fd
;
1367 cfg
.format
= exynos5_format_to_s3c_format(handle
->format
);
1368 cfg
.offset
= offset
;
1369 cfg
.stride
= handle
->stride
* bpp
/ 8;
1370 cfg
.blending
= exynos5_blending_to_s3c_blending(blending
);
1371 cfg
.fence_fd
= fence_fd
;
1374 static void exynos5_config_overlay(hwc_layer_1_t
*layer
, s3c_fb_win_config
&cfg
,
1375 exynos5_hwc_composer_device_1_t
*pdev
)
1377 if (layer
->compositionType
== HWC_BACKGROUND
) {
1378 hwc_color_t color
= layer
->backgroundColor
;
1379 cfg
.state
= cfg
.S3C_FB_WIN_STATE_COLOR
;
1380 cfg
.color
= (color
.r
<< 16) | (color
.g
<< 8) | color
.b
;
1388 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
->handle
);
1389 exynos5_config_handle(handle
, layer
->sourceCrop
, layer
->displayFrame
,
1390 layer
->blending
, layer
->acquireFenceFd
, cfg
, pdev
);
1393 static int exynos5_post_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1394 hwc_display_contents_1_t
* contents
)
1396 exynos5_hwc_post_data_t
*pdata
= &pdev
->bufs
;
1397 struct s3c_fb_win_config_data win_data
;
1398 struct s3c_fb_win_config
*config
= win_data
.config
;
1400 memset(config
, 0, sizeof(win_data
.config
));
1401 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1402 config
[i
].fence_fd
= -1;
1404 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1405 int layer_idx
= pdata
->overlay_map
[i
];
1406 if (layer_idx
!= -1) {
1407 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1408 private_handle_t
*handle
=
1409 private_handle_t::dynamicCast(layer
.handle
);
1411 if (pdata
->gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1412 int gsc_idx
= pdata
->gsc_map
[i
].idx
;
1413 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1415 // RGBX8888 surfaces are already in the right color order from the GPU,
1416 // RGB565 and YUV surfaces need the Gscaler to swap R & B
1417 int dst_format
= HAL_PIXEL_FORMAT_BGRA_8888
;
1418 if (exynos5_format_is_rgb(handle
->format
) &&
1419 handle
->format
!= HAL_PIXEL_FORMAT_RGB_565
)
1420 dst_format
= HAL_PIXEL_FORMAT_RGBX_8888
;
1422 hwc_rect_t sourceCrop
= { 0, 0,
1423 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
) };
1424 int err
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
,
1425 gsc_idx
, dst_format
, &sourceCrop
);
1427 ALOGE("failed to configure gscaler %u for layer %u",
1429 pdata
->gsc_map
[i
].mode
= exynos5_gsc_map_t::GSC_NONE
;
1433 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1434 private_handle_t
*dst_handle
=
1435 private_handle_t::dynamicCast(dst_buf
);
1436 int fence
= gsc
.dst_cfg
.releaseFenceFd
;
1437 exynos5_config_handle(dst_handle
, sourceCrop
,
1438 layer
.displayFrame
, layer
.blending
, fence
, config
[i
],
1441 exynos5_config_overlay(&layer
, config
[i
], pdev
);
1444 if (i
== 0 && config
[i
].blending
!= S3C_FB_BLENDING_NONE
) {
1445 ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
1446 config
[i
].blending
= S3C_FB_BLENDING_NONE
;
1449 ALOGV("window %u configuration:", i
);
1450 dump_config(config
[i
]);
1453 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1454 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1455 if (config
[i
].fence_fd
!= -1)
1456 close(config
[i
].fence_fd
);
1458 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %s", strerror(errno
));
1462 memcpy(pdev
->last_config
, &win_data
.config
, sizeof(win_data
.config
));
1463 memcpy(pdev
->last_gsc_map
, pdata
->gsc_map
, sizeof(pdata
->gsc_map
));
1464 pdev
->last_fb_window
= pdata
->fb_window
;
1465 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1466 int layer_idx
= pdata
->overlay_map
[i
];
1467 if (layer_idx
!= -1) {
1468 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1469 pdev
->last_handles
[i
] = layer
.handle
;
1473 return win_data
.fence
;
1476 static int exynos5_clear_fimd(exynos5_hwc_composer_device_1_t
*pdev
)
1478 struct s3c_fb_win_config_data win_data
;
1479 memset(&win_data
, 0, sizeof(win_data
));
1481 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1482 LOG_ALWAYS_FATAL_IF(ret
< 0,
1483 "ioctl S3CFB_WIN_CONFIG failed to clear screen: %s",
1485 // the causes of an empty config failing are all unrecoverable
1487 return win_data
.fence
;
1490 static int exynos5_set_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1491 hwc_display_contents_1_t
* contents
)
1493 hwc_layer_1_t
*fb_layer
= NULL
;
1496 if (pdev
->bufs
.fb_window
!= NO_FB_NEEDED
) {
1497 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1498 if (contents
->hwLayers
[i
].compositionType
==
1499 HWC_FRAMEBUFFER_TARGET
) {
1500 pdev
->bufs
.overlay_map
[pdev
->bufs
.fb_window
] = i
;
1501 fb_layer
= &contents
->hwLayers
[i
];
1506 if (CC_UNLIKELY(!fb_layer
)) {
1507 ALOGE("framebuffer target expected, but not provided");
1510 ALOGV("framebuffer target buffer:");
1511 dump_layer(fb_layer
);
1517 fence
= exynos5_post_fimd(pdev
, contents
);
1523 fence
= exynos5_clear_fimd(pdev
);
1525 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1526 if (pdev
->bufs
.overlay_map
[i
] != -1) {
1527 hwc_layer_1_t
&layer
=
1528 contents
->hwLayers
[pdev
->bufs
.overlay_map
[i
]];
1529 int dup_fd
= dup_or_warn(fence
);
1530 if (pdev
->bufs
.gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1531 int gsc_idx
= pdev
->bufs
.gsc_map
[i
].idx
;
1532 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1533 gsc
.dst_buf_fence
[gsc
.current_buf
] = dup_fd
;
1534 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1536 layer
.releaseFenceFd
= dup_fd
;
1540 contents
->retireFenceFd
= fence
;
1545 static int exynos5_set_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1546 hwc_display_contents_1_t
* contents
)
1548 hwc_layer_1_t
*video_layer
= NULL
;
1550 if (!pdev
->hdmi_enabled
) {
1551 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1552 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1553 if (layer
.acquireFenceFd
!= -1) {
1554 close(layer
.acquireFenceFd
);
1555 layer
.acquireFenceFd
= -1;
1561 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1562 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1564 if (layer
.flags
& HWC_SKIP_LAYER
) {
1565 ALOGV("HDMI skipping layer %d", i
);
1569 if (layer
.compositionType
== HWC_OVERLAY
) {
1573 ALOGV("HDMI video layer:");
1576 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[HDMI_GSC_IDX
];
1577 int ret
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
, 1,
1578 HAL_PIXEL_FORMAT_RGBX_8888
, NULL
);
1580 ALOGE("failed to configure gscaler for video layer");
1584 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1585 private_handle_t
*h
= private_handle_t::dynamicCast(dst_buf
);
1587 int acquireFenceFd
= gsc
.dst_cfg
.releaseFenceFd
;
1588 int releaseFenceFd
= -1;
1590 hdmi_output(pdev
, pdev
->hdmi_layers
[0], layer
, h
, acquireFenceFd
,
1592 video_layer
= &layer
;
1594 gsc
.dst_buf_fence
[gsc
.current_buf
] = releaseFenceFd
;
1595 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1596 if (contents
->retireFenceFd
< 0)
1597 contents
->retireFenceFd
= dup_or_warn(releaseFenceFd
);
1599 int merged
= merge_or_warn("hdmi",
1600 contents
->retireFenceFd
, layer
.releaseFenceFd
);
1601 close(contents
->retireFenceFd
);
1602 contents
->retireFenceFd
= merged
;
1606 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1607 if (pdev
->hdmi_fb_needed
&& layer
.handle
) {
1608 ALOGV("HDMI FB layer:");
1611 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1612 hdmi_show_layer(pdev
, pdev
->hdmi_layers
[1]);
1613 hdmi_output(pdev
, pdev
->hdmi_layers
[1], layer
, h
, layer
.acquireFenceFd
,
1614 &layer
.releaseFenceFd
);
1616 if (contents
->retireFenceFd
< 0)
1617 contents
->retireFenceFd
= dup_or_warn(layer
.releaseFenceFd
);
1619 int merged
= merge_or_warn("hdmi",
1620 contents
->retireFenceFd
, layer
.releaseFenceFd
);
1621 close(contents
->retireFenceFd
);
1622 contents
->retireFenceFd
= merged
;
1625 hdmi_hide_layer(pdev
, pdev
->hdmi_layers
[1]);
1631 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[0]);
1632 exynos5_cleanup_gsc_m2m(pdev
, HDMI_GSC_IDX
);
1635 if (exynos_v4l2_s_ctrl(pdev
->hdmi_layers
[1].fd
, V4L2_CID_TV_UPDATE
, 1) < 0) {
1636 ALOGE("%s: s_ctrl(CID_TV_UPDATE) failed %d", __func__
, errno
);
1643 static int exynos5_set(struct hwc_composer_device_1
*dev
,
1644 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1646 if (!numDisplays
|| !displays
)
1649 exynos5_hwc_composer_device_1_t
*pdev
=
1650 (exynos5_hwc_composer_device_1_t
*)dev
;
1651 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1652 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1653 int fimd_err
= 0, hdmi_err
= 0;
1656 fimd_err
= exynos5_set_fimd(pdev
, fimd_contents
);
1659 hdmi_err
= exynos5_set_hdmi(pdev
, hdmi_contents
);
1667 static void exynos5_registerProcs(struct hwc_composer_device_1
* dev
,
1668 hwc_procs_t
const* procs
)
1670 struct exynos5_hwc_composer_device_1_t
* pdev
=
1671 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1672 pdev
->procs
= procs
;
1675 static int exynos5_query(struct hwc_composer_device_1
* dev
, int what
, int *value
)
1677 struct exynos5_hwc_composer_device_1_t
*pdev
=
1678 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1681 case HWC_BACKGROUND_LAYER_SUPPORTED
:
1682 // we support the background layer
1685 case HWC_VSYNC_PERIOD
:
1686 // vsync period in nanosecond
1687 value
[0] = pdev
->vsync_period
;
1690 // unsupported query
1696 static int exynos5_eventControl(struct hwc_composer_device_1
*dev
, int dpy
,
1697 int event
, int enabled
)
1699 struct exynos5_hwc_composer_device_1_t
*pdev
=
1700 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1703 case HWC_EVENT_VSYNC
:
1704 __u32 val
= !!enabled
;
1705 int err
= ioctl(pdev
->fd
, S3CFB_SET_VSYNC_INT
, &val
);
1707 ALOGE("vsync ioctl failed");
1717 static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t
*pdev
,
1718 const char *buff
, int len
)
1720 const char *s
= buff
;
1724 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1725 pdev
->hdmi_hpd
= atoi(s
+ strlen("SWITCH_STATE=")) == 1;
1728 if (s
- buff
>= len
)
1732 if (pdev
->hdmi_hpd
) {
1733 if (hdmi_get_config(pdev
)) {
1734 ALOGE("Error reading HDMI configuration");
1735 pdev
->hdmi_hpd
= false;
1739 pdev
->hdmi_blanked
= false;
1742 ALOGV("HDMI HPD changed to %s", pdev
->hdmi_hpd
? "enabled" : "disabled");
1744 ALOGI("HDMI Resolution changed to %dx%d", pdev
->hdmi_h
, pdev
->hdmi_w
);
1746 /* hwc_dev->procs is set right after the device is opened, but there is
1747 * still a race condition where a hotplug event might occur after the open
1748 * but before the procs are registered. */
1750 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, pdev
->hdmi_hpd
);
1753 static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t
*pdev
)
1758 int err
= lseek(pdev
->vsync_fd
, 0, SEEK_SET
);
1760 ALOGE("error seeking to vsync timestamp: %s", strerror(errno
));
1765 err
= read(pdev
->vsync_fd
, buf
, sizeof(buf
));
1767 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1770 buf
[sizeof(buf
) - 1] = '\0';
1773 uint64_t timestamp
= strtoull(buf
, NULL
, 0);
1775 pdev
->procs
->vsync(pdev
->procs
, 0, timestamp
);
1778 static void *hwc_vsync_thread(void *data
)
1780 struct exynos5_hwc_composer_device_1_t
*pdev
=
1781 (struct exynos5_hwc_composer_device_1_t
*)data
;
1782 char uevent_desc
[4096];
1783 memset(uevent_desc
, 0, sizeof(uevent_desc
));
1785 setpriority(PRIO_PROCESS
, 0, HAL_PRIORITY_URGENT_DISPLAY
);
1790 int err
= read(pdev
->vsync_fd
, temp
, sizeof(temp
));
1792 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1796 struct pollfd fds
[2];
1797 fds
[0].fd
= pdev
->vsync_fd
;
1798 fds
[0].events
= POLLPRI
;
1799 fds
[1].fd
= uevent_get_fd();
1800 fds
[1].events
= POLLIN
;
1803 int err
= poll(fds
, 2, -1);
1806 if (fds
[0].revents
& POLLPRI
) {
1807 handle_vsync_event(pdev
);
1809 else if (fds
[1].revents
& POLLIN
) {
1810 int len
= uevent_next_event(uevent_desc
,
1811 sizeof(uevent_desc
) - 2);
1813 bool hdmi
= !strcmp(uevent_desc
,
1814 "change@/devices/virtual/switch/hdmi");
1816 handle_hdmi_uevent(pdev
, uevent_desc
, len
);
1819 else if (err
== -1) {
1822 ALOGE("error in vsync thread: %s", strerror(errno
));
1829 static int exynos5_blank(struct hwc_composer_device_1
*dev
, int disp
, int blank
)
1831 struct exynos5_hwc_composer_device_1_t
*pdev
=
1832 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1835 case HWC_DISPLAY_PRIMARY
: {
1836 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
1837 int err
= ioctl(pdev
->fd
, FBIOBLANK
, fb_blank
);
1840 ALOGI("%sblank ioctl failed (display already %sblanked)",
1841 blank
? "" : "un", blank
? "" : "un");
1843 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
1850 case HWC_DISPLAY_EXTERNAL
:
1851 if (pdev
->hdmi_hpd
) {
1852 if (blank
&& !pdev
->hdmi_blanked
)
1854 pdev
->hdmi_blanked
= !!blank
;
1866 static void exynos5_dump(hwc_composer_device_1
* dev
, char *buff
, int buff_len
)
1871 struct exynos5_hwc_composer_device_1_t
*pdev
=
1872 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1874 android::String8 result
;
1876 result
.appendFormat(" hdmi_enabled=%u\n", pdev
->hdmi_enabled
);
1877 if (pdev
->hdmi_enabled
)
1878 result
.appendFormat(" w=%u, h=%u\n", pdev
->hdmi_w
, pdev
->hdmi_h
);
1880 " type | handle | color | blend | format | position | size | gsc \n"
1881 "----------+----------|----------+-------+--------+---------------+---------------------\n");
1882 // 8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
1884 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1885 struct s3c_fb_win_config
&config
= pdev
->last_config
[i
];
1886 if (config
.state
== config
.S3C_FB_WIN_STATE_DISABLED
) {
1887 result
.appendFormat(" %8s | %8s | %8s | %5s | %6s | %13s | %13s",
1888 "DISABLED", "-", "-", "-", "-", "-", "-");
1891 if (config
.state
== config
.S3C_FB_WIN_STATE_COLOR
)
1892 result
.appendFormat(" %8s | %8s | %8x | %5s | %6s", "COLOR",
1893 "-", config
.color
, "-", "-");
1895 result
.appendFormat(" %8s | %8x | %8s | %5x | %6x",
1896 pdev
->last_fb_window
== i
? "FB" : "OVERLAY",
1897 intptr_t(pdev
->last_handles
[i
]),
1898 "-", config
.blending
, config
.format
);
1900 result
.appendFormat(" | [%5d,%5d] | [%5u,%5u]", config
.x
, config
.y
,
1901 config
.w
, config
.h
);
1903 if (pdev
->last_gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_NONE
)
1904 result
.appendFormat(" | %3s", "-");
1906 result
.appendFormat(" | %3d",
1907 AVAILABLE_GSC_UNITS
[pdev
->last_gsc_map
[i
].idx
]);
1908 result
.append("\n");
1911 strlcpy(buff
, result
.string(), buff_len
);
1914 static int exynos5_getDisplayConfigs(struct hwc_composer_device_1
*dev
,
1915 int disp
, uint32_t *configs
, size_t *numConfigs
)
1917 struct exynos5_hwc_composer_device_1_t
*pdev
=
1918 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1920 if (*numConfigs
== 0)
1923 if (disp
== HWC_DISPLAY_PRIMARY
) {
1927 } else if (disp
== HWC_DISPLAY_EXTERNAL
) {
1928 if (!pdev
->hdmi_hpd
) {
1932 int err
= hdmi_get_config(pdev
);
1945 static int32_t exynos5_fimd_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1946 const uint32_t attribute
)
1949 case HWC_DISPLAY_VSYNC_PERIOD
:
1950 return pdev
->vsync_period
;
1952 case HWC_DISPLAY_WIDTH
:
1955 case HWC_DISPLAY_HEIGHT
:
1958 case HWC_DISPLAY_DPI_X
:
1961 case HWC_DISPLAY_DPI_Y
:
1965 ALOGE("unknown display attribute %u", attribute
);
1970 static int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1971 const uint32_t attribute
)
1974 case HWC_DISPLAY_VSYNC_PERIOD
:
1975 return pdev
->vsync_period
;
1977 case HWC_DISPLAY_WIDTH
:
1978 return pdev
->hdmi_w
;
1980 case HWC_DISPLAY_HEIGHT
:
1981 return pdev
->hdmi_h
;
1983 case HWC_DISPLAY_DPI_X
:
1984 case HWC_DISPLAY_DPI_Y
:
1985 return 0; // unknown
1988 ALOGE("unknown display attribute %u", attribute
);
1993 static int exynos5_getDisplayAttributes(struct hwc_composer_device_1
*dev
,
1994 int disp
, uint32_t config
, const uint32_t *attributes
, int32_t *values
)
1996 struct exynos5_hwc_composer_device_1_t
*pdev
=
1997 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1999 for (int i
= 0; attributes
[i
] != HWC_DISPLAY_NO_ATTRIBUTE
; i
++) {
2000 if (disp
== HWC_DISPLAY_PRIMARY
)
2001 values
[i
] = exynos5_fimd_attribute(pdev
, attributes
[i
]);
2002 else if (disp
== HWC_DISPLAY_EXTERNAL
)
2003 values
[i
] = exynos5_hdmi_attribute(pdev
, attributes
[i
]);
2005 ALOGE("unknown display type %u", disp
);
2013 static int exynos5_close(hw_device_t
* device
);
2015 static void get_screen_res(const char *fbname
, int32_t *xres
, int32_t *yres
,
2022 unsigned int _x
, _y
, _r
;
2024 asprintf(&path
, "/sys/class/graphics/%s/modes", fbname
);
2027 fd
= open(path
, O_RDONLY
);
2030 ret
= read(fd
, buf
, sizeof(buf
));
2033 buf
[sizeof(buf
)-1] = '\0';
2035 ret
= sscanf(buf
, "U:%ux%up-%u", &_x
, &_y
, &_r
);
2039 ALOGI("Using %ux%u %uHz resolution for '%s' from modes list\n",
2040 _x
, _y
, _r
, fbname
);
2042 *xres
= (int32_t)_x
;
2043 *yres
= (int32_t)_y
;
2044 *refresh
= (int32_t)_r
;
2061 static int exynos5_open(const struct hw_module_t
*module
, const char *name
,
2062 struct hw_device_t
**device
)
2068 if (strcmp(name
, HWC_HARDWARE_COMPOSER
)) {
2072 struct exynos5_hwc_composer_device_1_t
*dev
;
2073 dev
= (struct exynos5_hwc_composer_device_1_t
*)malloc(sizeof(*dev
));
2074 memset(dev
, 0, sizeof(*dev
));
2076 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
,
2077 (const struct hw_module_t
**)&dev
->gralloc_module
)) {
2078 ALOGE("failed to get gralloc hw module");
2080 goto err_get_module
;
2083 if (gralloc_open((const hw_module_t
*)dev
->gralloc_module
,
2084 &dev
->alloc_device
)) {
2085 ALOGE("failed to open gralloc");
2087 goto err_get_module
;
2090 dev
->fd
= open("/dev/graphics/fb0", O_RDWR
);
2092 ALOGE("failed to open framebuffer");
2097 struct fb_var_screeninfo info
;
2098 if (ioctl(dev
->fd
, FBIOGET_VSCREENINFO
, &info
) == -1) {
2099 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno
));
2104 get_screen_res("fb0", &dev
->xres
, &dev
->yres
, &refreshRate
);
2105 if (refreshRate
== 0) {
2106 ALOGW("invalid refresh rate, assuming 60 Hz");
2110 dev
->xdpi
= 1000 * (dev
->xres
* 25.4f
) / info
.width
;
2111 dev
->ydpi
= 1000 * (dev
->yres
* 25.4f
) / info
.height
;
2112 dev
->vsync_period
= 1000000000 / refreshRate
;
2117 "width = %d mm (%f dpi)\n"
2118 "height = %d mm (%f dpi)\n"
2119 "refresh rate = %d Hz\n",
2120 dev
->xres
, dev
->yres
, info
.width
, dev
->xdpi
/ 1000.0,
2121 info
.height
, dev
->ydpi
/ 1000.0, refreshRate
);
2123 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2124 for (size_t j
= 0; j
< NUM_GSC_DST_BUFS
; j
++)
2125 dev
->gsc
[i
].dst_buf_fence
[j
] = -1;
2127 dev
->hdmi_mixer0
= open("/dev/v4l-subdev7", O_RDWR
);
2128 if (dev
->hdmi_mixer0
< 0)
2129 ALOGE("failed to open hdmi mixer0 subdev");
2131 dev
->hdmi_layers
[0].id
= 0;
2132 dev
->hdmi_layers
[0].fd
= open("/dev/video16", O_RDWR
);
2133 if (dev
->hdmi_layers
[0].fd
< 0) {
2134 ALOGE("failed to open hdmi layer0 device");
2135 ret
= dev
->hdmi_layers
[0].fd
;
2139 dev
->hdmi_layers
[1].id
= 1;
2140 dev
->hdmi_layers
[1].fd
= open("/dev/video17", O_RDWR
);
2141 if (dev
->hdmi_layers
[1].fd
< 0) {
2142 ALOGE("failed to open hdmi layer1 device");
2143 ret
= dev
->hdmi_layers
[1].fd
;
2147 dev
->vsync_fd
= open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY
);
2148 if (dev
->vsync_fd
< 0) {
2149 ALOGE("failed to open vsync attribute");
2150 ret
= dev
->vsync_fd
;
2154 sw_fd
= open("/sys/class/switch/hdmi/state", O_RDONLY
);
2157 if (read(sw_fd
, &val
, 1) == 1 && val
== '1') {
2158 dev
->hdmi_hpd
= true;
2159 if (hdmi_get_config(dev
)) {
2160 ALOGE("Error reading HDMI configuration");
2161 dev
->hdmi_hpd
= false;
2166 dev
->base
.common
.tag
= HARDWARE_DEVICE_TAG
;
2167 dev
->base
.common
.version
= HWC_DEVICE_API_VERSION_1_1
;
2168 dev
->base
.common
.module
= const_cast<hw_module_t
*>(module
);
2169 dev
->base
.common
.close
= exynos5_close
;
2171 dev
->base
.prepare
= exynos5_prepare
;
2172 dev
->base
.set
= exynos5_set
;
2173 dev
->base
.eventControl
= exynos5_eventControl
;
2174 dev
->base
.blank
= exynos5_blank
;
2175 dev
->base
.query
= exynos5_query
;
2176 dev
->base
.registerProcs
= exynos5_registerProcs
;
2177 dev
->base
.dump
= exynos5_dump
;
2178 dev
->base
.getDisplayConfigs
= exynos5_getDisplayConfigs
;
2179 dev
->base
.getDisplayAttributes
= exynos5_getDisplayAttributes
;
2181 *device
= &dev
->base
.common
;
2183 ret
= pthread_create(&dev
->vsync_thread
, NULL
, hwc_vsync_thread
, dev
);
2185 ALOGE("failed to start vsync thread: %s", strerror(ret
));
2190 char value
[PROPERTY_VALUE_MAX
];
2191 property_get("debug.hwc.force_gpu", value
, "0");
2192 dev
->force_gpu
= atoi(value
);
2197 close(dev
->vsync_fd
);
2199 if (dev
->hdmi_mixer0
>= 0)
2200 close(dev
->hdmi_mixer0
);
2202 close(dev
->hdmi_layers
[0].fd
);
2204 close(dev
->hdmi_layers
[1].fd
);
2208 gralloc_close(dev
->alloc_device
);
2214 static int exynos5_close(hw_device_t
*device
)
2216 struct exynos5_hwc_composer_device_1_t
*dev
=
2217 (struct exynos5_hwc_composer_device_1_t
*)device
;
2218 pthread_kill(dev
->vsync_thread
, SIGTERM
);
2219 pthread_join(dev
->vsync_thread
, NULL
);
2220 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2221 exynos5_cleanup_gsc_m2m(dev
, i
);
2222 gralloc_close(dev
->alloc_device
);
2223 close(dev
->vsync_fd
);
2224 if (dev
->hdmi_mixer0
>= 0)
2225 close(dev
->hdmi_mixer0
);
2226 close(dev
->hdmi_layers
[0].fd
);
2227 close(dev
->hdmi_layers
[1].fd
);
2232 static struct hw_module_methods_t exynos5_hwc_module_methods
= {
2236 hwc_module_t HAL_MODULE_INFO_SYM
= {
2238 tag
: HARDWARE_MODULE_TAG
,
2239 module_api_version
: HWC_MODULE_API_VERSION_0_1
,
2240 hal_api_version
: HARDWARE_HAL_API_VERSION
,
2241 id
: HWC_HARDWARE_MODULE_ID
,
2242 name
: "Samsung exynos5 hwcomposer module",
2244 methods
: &exynos5_hwc_module_methods
,