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.
23 #include <sys/ioctl.h>
26 #include <sys/resource.h>
32 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
34 #include <cutils/compiler.h>
35 #include <cutils/log.h>
36 #include <cutils/properties.h>
37 #include <hardware/gralloc.h>
38 #include <hardware/hardware.h>
39 #include <hardware/hwcomposer.h>
40 #include <hardware_legacy/uevent.h>
41 #include <utils/String8.h>
42 #include <utils/Vector.h>
44 #include <sync/sync.h>
47 #include "gralloc_priv.h"
48 #include "exynos_gscaler.h"
49 #include "exynos_format.h"
50 #include "exynos_v4l2.h"
51 #include "s5p_tvout_v4l2.h"
53 const size_t NUM_HW_WINDOWS
= 5;
54 const size_t NO_FB_NEEDED
= NUM_HW_WINDOWS
+ 1;
55 const size_t MAX_PIXELS
= 2560 * 1600 * 2;
56 const size_t GSC_W_ALIGNMENT
= 16;
57 const size_t GSC_H_ALIGNMENT
= 16;
58 const size_t GSC_DST_W_ALIGNMENT_RGB888
= 32;
59 const size_t GSC_DST_H_ALIGNMENT_RGB888
= 1;
60 const size_t FIMD_GSC_IDX
= 0;
61 const size_t HDMI_GSC_IDX
= 1;
62 const int AVAILABLE_GSC_UNITS
[] = { 0, 3 };
63 const size_t NUM_GSC_UNITS
= sizeof(AVAILABLE_GSC_UNITS
) /
64 sizeof(AVAILABLE_GSC_UNITS
[0]);
65 const size_t BURSTLEN_BYTES
= 16 * 8;
66 const size_t NUM_HDMI_BUFFERS
= 3;
68 struct exynos5_hwc_composer_device_1_t
;
70 struct exynos5_gsc_map_t
{
74 // TODO: GSC_LOCAL_PATH
79 struct exynos5_hwc_post_data_t
{
80 int overlay_map
[NUM_HW_WINDOWS
];
81 exynos5_gsc_map_t gsc_map
[NUM_HW_WINDOWS
];
85 const size_t NUM_GSC_DST_BUFS
= 3;
86 struct exynos5_gsc_data_t
{
88 exynos_gsc_img src_cfg
;
89 exynos_gsc_img dst_cfg
;
90 buffer_handle_t dst_buf
[NUM_GSC_DST_BUFS
];
105 struct exynos5_hwc_composer_device_1_t
{
106 hwc_composer_device_1_t base
;
110 exynos5_hwc_post_data_t bufs
;
112 const private_module_t
*gralloc_module
;
113 alloc_device_t
*alloc_device
;
114 const hwc_procs_t
*procs
;
115 pthread_t vsync_thread
;
122 int32_t vsync_period
;
131 hdmi_layer_t hdmi_layers
[2];
133 exynos5_gsc_data_t gsc
[NUM_GSC_UNITS
];
135 struct s3c_fb_win_config last_config
[NUM_HW_WINDOWS
];
136 size_t last_fb_window
;
137 const void *last_handles
[NUM_HW_WINDOWS
];
138 exynos5_gsc_map_t last_gsc_map
[NUM_HW_WINDOWS
];
141 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
144 static void dump_handle(private_handle_t
*h
)
146 ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
147 h
->format
, h
->width
, h
->height
, h
->stride
, h
->vstride
);
150 static void dump_layer(hwc_layer_1_t
const *l
)
152 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
153 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
154 l
->compositionType
, l
->flags
, l
->handle
, l
->transform
,
159 l
->sourceCrop
.bottom
,
160 l
->displayFrame
.left
,
162 l
->displayFrame
.right
,
163 l
->displayFrame
.bottom
);
165 if(l
->handle
&& !(l
->flags
& HWC_SKIP_LAYER
))
166 dump_handle(private_handle_t::dynamicCast(l
->handle
));
169 static void dump_config(s3c_fb_win_config
&c
)
171 ALOGV("\tstate = %u", c
.state
);
172 if (c
.state
== c
.S3C_FB_WIN_STATE_BUFFER
) {
173 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
174 "x = %d, y = %d, w = %u, h = %u, "
175 "format = %u, blending = %u",
176 c
.fd
, c
.offset
, c
.stride
,
178 c
.format
, c
.blending
);
180 else if (c
.state
== c
.S3C_FB_WIN_STATE_COLOR
) {
181 ALOGV("\t\tcolor = %u", c
.color
);
185 static void dump_gsc_img(exynos_gsc_img
&c
)
187 ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
188 c
.x
, c
.y
, c
.w
, c
.h
, c
.fw
, c
.fh
);
189 ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
190 c
.yaddr
, c
.uaddr
, c
.vaddr
, c
.rot
, c
.cacheable
, c
.drmMode
);
193 inline int WIDTH(const hwc_rect
&rect
) { return rect
.right
- rect
.left
; }
194 inline int HEIGHT(const hwc_rect
&rect
) { return rect
.bottom
- rect
.top
; }
195 template<typename T
> inline T
max(T a
, T b
) { return (a
> b
) ? a
: b
; }
196 template<typename T
> inline T
min(T a
, T b
) { return (a
< b
) ? a
: b
; }
198 static bool is_transformed(const hwc_layer_1_t
&layer
)
200 return layer
.transform
!= 0;
203 static bool is_rotated(const hwc_layer_1_t
&layer
)
205 return (layer
.transform
& HAL_TRANSFORM_ROT_90
) ||
206 (layer
.transform
& HAL_TRANSFORM_ROT_180
);
209 static bool is_scaled(const hwc_layer_1_t
&layer
)
211 return WIDTH(layer
.displayFrame
) != WIDTH(layer
.sourceCrop
) ||
212 HEIGHT(layer
.displayFrame
) != HEIGHT(layer
.sourceCrop
);
215 static inline bool gsc_dst_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
217 return c1
.x
!= c2
.x
||
221 c1
.format
!= c2
.format
||
223 c1
.cacheable
!= c2
.cacheable
||
224 c1
.drmMode
!= c2
.drmMode
;
227 static inline bool gsc_src_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
229 return gsc_dst_cfg_changed(c1
, c2
) ||
234 static enum s3c_fb_pixel_format
exynos5_format_to_s3c_format(int format
)
237 case HAL_PIXEL_FORMAT_RGBA_8888
:
238 return S3C_FB_PIXEL_FORMAT_RGBA_8888
;
239 case HAL_PIXEL_FORMAT_RGBX_8888
:
240 return S3C_FB_PIXEL_FORMAT_RGBX_8888
;
241 case HAL_PIXEL_FORMAT_RGBA_5551
:
242 return S3C_FB_PIXEL_FORMAT_RGBA_5551
;
243 case HAL_PIXEL_FORMAT_RGB_565
:
244 return S3C_FB_PIXEL_FORMAT_RGB_565
;
245 case HAL_PIXEL_FORMAT_BGRA_8888
:
246 return S3C_FB_PIXEL_FORMAT_BGRA_8888
;
248 return S3C_FB_PIXEL_FORMAT_MAX
;
252 static bool exynos5_format_is_supported(int format
)
254 return exynos5_format_to_s3c_format(format
) < S3C_FB_PIXEL_FORMAT_MAX
;
257 static bool exynos5_format_is_rgb(int format
)
260 case HAL_PIXEL_FORMAT_RGBA_8888
:
261 case HAL_PIXEL_FORMAT_RGBX_8888
:
262 case HAL_PIXEL_FORMAT_RGB_888
:
263 case HAL_PIXEL_FORMAT_RGB_565
:
264 case HAL_PIXEL_FORMAT_BGRA_8888
:
265 case HAL_PIXEL_FORMAT_RGBA_5551
:
266 case HAL_PIXEL_FORMAT_RGBA_4444
:
274 static bool exynos5_format_is_supported_by_gscaler(int format
)
277 case HAL_PIXEL_FORMAT_RGBX_8888
:
278 case HAL_PIXEL_FORMAT_RGB_565
:
279 case HAL_PIXEL_FORMAT_EXYNOS_YV12
:
280 case HAL_PIXEL_FORMAT_YCbCr_420_SP
:
281 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED
:
289 static bool exynos5_format_is_ycrcb(int format
)
291 return format
== HAL_PIXEL_FORMAT_EXYNOS_YV12
;
294 static bool exynos5_format_requires_gscaler(int format
)
296 return (exynos5_format_is_supported_by_gscaler(format
) &&
297 (format
!= HAL_PIXEL_FORMAT_RGBX_8888
) && (format
!= HAL_PIXEL_FORMAT_RGB_565
));
300 static uint8_t exynos5_format_to_bpp(int format
)
303 case HAL_PIXEL_FORMAT_RGBA_8888
:
304 case HAL_PIXEL_FORMAT_RGBX_8888
:
305 case HAL_PIXEL_FORMAT_BGRA_8888
:
308 case HAL_PIXEL_FORMAT_RGBA_5551
:
309 case HAL_PIXEL_FORMAT_RGBA_4444
:
310 case HAL_PIXEL_FORMAT_RGB_565
:
314 ALOGW("unrecognized pixel format %u", format
);
319 static bool is_x_aligned(const hwc_layer_1_t
&layer
, int format
)
321 if (!exynos5_format_is_supported(format
))
324 uint8_t bpp
= exynos5_format_to_bpp(format
);
325 uint8_t pixel_alignment
= 32 / bpp
;
327 return (layer
.displayFrame
.left
% pixel_alignment
) == 0 &&
328 (layer
.displayFrame
.right
% pixel_alignment
) == 0;
331 static bool dst_crop_w_aligned(const hwc_layer_1_t
&layer
, int format
)
334 int dst_crop_w_alignement
;
336 dest_w
= WIDTH(layer
.displayFrame
);
338 /* GSC's dst crop size should be aligned 128Bytes */
339 dst_crop_w_alignement
= 32;
341 return (dest_w
% dst_crop_w_alignement
) == 0;
344 static bool exynos5_supports_gscaler(hwc_layer_1_t
&layer
, int format
,
347 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
349 int max_w
= is_rotated(layer
) ? 2048 : 4800;
350 int max_h
= is_rotated(layer
) ? 2048 : 3344;
352 bool rot90or270
= !!(layer
.transform
& HAL_TRANSFORM_ROT_90
);
353 // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
354 // HAL_TRANSFORM_ROT_180
356 int src_w
= WIDTH(layer
.sourceCrop
), src_h
= HEIGHT(layer
.sourceCrop
);
359 dest_w
= HEIGHT(layer
.displayFrame
);
360 dest_h
= WIDTH(layer
.displayFrame
);
362 dest_w
= WIDTH(layer
.displayFrame
);
363 dest_h
= HEIGHT(layer
.displayFrame
);
365 int max_downscale
= local_path
? 4 : 16;
366 const int max_upscale
= 8;
368 return exynos5_format_is_supported_by_gscaler(format
) &&
369 dst_crop_w_aligned(layer
,format
) &&
370 handle
->stride
<= max_w
&&
371 handle
->stride
% GSC_W_ALIGNMENT
== 0 &&
372 src_w
<= dest_w
* max_downscale
&&
373 dest_w
<= src_w
* max_upscale
&&
374 handle
->vstride
<= max_h
&&
375 handle
->vstride
% GSC_H_ALIGNMENT
== 0 &&
376 src_h
<= dest_h
* max_downscale
&&
377 dest_h
<= src_h
* max_upscale
&&
379 (!rot90or270
|| layer
.sourceCrop
.top
% 2 == 0) &&
380 (!rot90or270
|| layer
.sourceCrop
.left
% 2 == 0);
384 static bool exynos5_requires_gscaler(hwc_layer_1_t
&layer
, int format
)
386 return exynos5_format_requires_gscaler(format
) || is_scaled(layer
)
387 || is_transformed(layer
) || !is_x_aligned(layer
, format
);
390 int hdmi_get_config(struct exynos5_hwc_composer_device_1_t
*dev
)
392 struct v4l2_dv_preset preset
;
393 struct v4l2_dv_enum_preset enum_preset
;
398 if (ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_G_DV_PRESET
, &preset
) < 0) {
399 ALOGE("%s: g_dv_preset error, %d", __func__
, errno
);
404 enum_preset
.index
= index
++;
405 ret
= ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_ENUM_DV_PRESETS
, &enum_preset
);
410 ALOGE("%s: enum_dv_presets error, %d", __func__
, errno
);
414 ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
415 __func__
, enum_preset
.index
, enum_preset
.preset
,
416 enum_preset
.width
, enum_preset
.height
, enum_preset
.name
);
418 if (preset
.preset
== enum_preset
.preset
) {
419 dev
->hdmi_w
= enum_preset
.width
;
420 dev
->hdmi_h
= enum_preset
.height
;
425 return found
? 0 : -1;
428 static enum s3c_fb_blending
exynos5_blending_to_s3c_blending(int32_t blending
)
431 case HWC_BLENDING_NONE
:
432 return S3C_FB_BLENDING_NONE
;
433 case HWC_BLENDING_PREMULT
:
434 return S3C_FB_BLENDING_PREMULT
;
435 case HWC_BLENDING_COVERAGE
:
436 return S3C_FB_BLENDING_COVERAGE
;
439 return S3C_FB_BLENDING_MAX
;
443 static bool exynos5_blending_is_supported(int32_t blending
)
445 return exynos5_blending_to_s3c_blending(blending
) < S3C_FB_BLENDING_MAX
;
449 static int hdmi_enable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
455 struct v4l2_requestbuffers reqbuf
;
456 memset(&reqbuf
, 0, sizeof(reqbuf
));
457 reqbuf
.count
= NUM_HDMI_BUFFERS
;
458 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
459 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
460 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0) {
461 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
465 if (reqbuf
.count
!= NUM_HDMI_BUFFERS
) {
466 ALOGE("%s: layer%d: didn't get buffer", __func__
, hl
.id
);
471 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_PIXEL_BLEND_ENABLE
, 1) < 0) {
472 ALOGE("%s: layer%d: PIXEL_BLEND_ENABLE failed %d", __func__
,
478 ALOGV("%s: layer%d enabled", __func__
, hl
.id
);
483 static void hdmi_disable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
490 if (exynos_v4l2_streamoff(hl
.fd
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) < 0)
491 ALOGE("%s: layer%d: streamoff failed %d", __func__
, hl
.id
, errno
);
492 hl
.streaming
= false;
495 struct v4l2_requestbuffers reqbuf
;
496 memset(&reqbuf
, 0, sizeof(reqbuf
));
497 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
498 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
499 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0)
500 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
502 memset(&hl
.cfg
, 0, sizeof(hl
.cfg
));
507 ALOGV("%s: layer%d disabled", __func__
, hl
.id
);
510 static int hdmi_enable(struct exynos5_hwc_composer_device_1_t
*dev
)
512 if (dev
->hdmi_enabled
)
515 if (dev
->hdmi_blanked
)
518 struct v4l2_subdev_format sd_fmt
;
519 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
520 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
521 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
522 sd_fmt
.format
.width
= dev
->hdmi_w
;
523 sd_fmt
.format
.height
= dev
->hdmi_h
;
524 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
525 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
526 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
530 struct v4l2_subdev_crop sd_crop
;
531 memset(&sd_crop
, 0, sizeof(sd_crop
));
532 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
533 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
534 sd_crop
.rect
.width
= dev
->hdmi_w
;
535 sd_crop
.rect
.height
= dev
->hdmi_h
;
536 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
537 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
541 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
542 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
543 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
544 sd_fmt
.format
.width
= dev
->hdmi_w
;
545 sd_fmt
.format
.height
= dev
->hdmi_h
;
546 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
547 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
548 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
552 memset(&sd_crop
, 0, sizeof(sd_crop
));
553 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
554 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
555 sd_crop
.rect
.width
= dev
->hdmi_w
;
556 sd_crop
.rect
.height
= dev
->hdmi_h
;
557 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
558 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
562 hdmi_enable_layer(dev
, dev
->hdmi_layers
[1]);
564 dev
->hdmi_enabled
= true;
568 static void hdmi_disable(struct exynos5_hwc_composer_device_1_t
*dev
)
570 if (!dev
->hdmi_enabled
)
573 hdmi_disable_layer(dev
, dev
->hdmi_layers
[0]);
574 hdmi_disable_layer(dev
, dev
->hdmi_layers
[1]);
576 exynos5_cleanup_gsc_m2m(dev
, HDMI_GSC_IDX
);
577 dev
->hdmi_enabled
= false;
580 static int hdmi_output(struct exynos5_hwc_composer_device_1_t
*dev
,
582 hwc_layer_1_t
&layer
,
590 memset(&cfg
, 0, sizeof(cfg
));
591 cfg
.x
= layer
.displayFrame
.left
;
592 cfg
.y
= layer
.displayFrame
.top
;
593 cfg
.w
= WIDTH(layer
.displayFrame
);
594 cfg
.h
= HEIGHT(layer
.displayFrame
);
596 if (gsc_src_cfg_changed(hl
.cfg
, cfg
)) {
597 hdmi_disable_layer(dev
, hl
);
599 struct v4l2_format fmt
;
600 memset(&fmt
, 0, sizeof(fmt
));
601 fmt
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
602 fmt
.fmt
.pix_mp
.width
= cfg
.w
;
603 fmt
.fmt
.pix_mp
.height
= cfg
.h
;
604 fmt
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_BGR32
;
605 fmt
.fmt
.pix_mp
.field
= V4L2_FIELD_ANY
;
606 fmt
.fmt
.pix_mp
.num_planes
= 1;
607 ret
= exynos_v4l2_s_fmt(hl
.fd
, &fmt
);
609 ALOGE("%s: layer%d: s_fmt failed %d", __func__
, hl
.id
, errno
);
613 struct v4l2_subdev_crop sd_crop
;
614 memset(&sd_crop
, 0, sizeof(sd_crop
));
616 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
618 sd_crop
.pad
= MIXER_G1_SUBDEV_PAD_SOURCE
;
619 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
620 sd_crop
.rect
.left
= cfg
.x
;
621 sd_crop
.rect
.top
= cfg
.y
;
622 sd_crop
.rect
.width
= cfg
.w
;
623 sd_crop
.rect
.height
= cfg
.h
;
624 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
625 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
629 hdmi_enable_layer(dev
, hl
);
631 ALOGV("HDMI layer%d configuration:", hl
.id
);
636 struct v4l2_buffer buffer
;
637 struct v4l2_plane planes
[1];
639 if (hl
.queued_buf
== NUM_HDMI_BUFFERS
) {
640 memset(&buffer
, 0, sizeof(buffer
));
641 memset(planes
, 0, sizeof(planes
));
642 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
643 buffer
.memory
= V4L2_MEMORY_DMABUF
;
645 buffer
.m
.planes
= planes
;
646 ret
= exynos_v4l2_dqbuf(hl
.fd
, &buffer
);
648 ALOGE("%s: layer%d: dqbuf failed %d", __func__
, hl
.id
, errno
);
654 memset(&buffer
, 0, sizeof(buffer
));
655 memset(planes
, 0, sizeof(planes
));
656 buffer
.index
= hl
.current_buf
;
657 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
658 buffer
.memory
= V4L2_MEMORY_DMABUF
;
659 buffer
.flags
= V4L2_BUF_FLAG_USE_SYNC
;
660 buffer
.reserved
= acquireFenceFd
;
662 buffer
.m
.planes
= planes
;
663 buffer
.m
.planes
[0].m
.fd
= h
->fd
;
664 if (exynos_v4l2_qbuf(hl
.fd
, &buffer
) < 0) {
665 ALOGE("%s: layer%d: qbuf failed %d", __func__
, hl
.id
, errno
);
671 *releaseFenceFd
= buffer
.reserved
;
673 close(buffer
.reserved
);
676 hl
.current_buf
= (hl
.current_buf
+ 1) % NUM_HDMI_BUFFERS
;
679 if (exynos_v4l2_streamon(hl
.fd
, buffer
.type
) < 0) {
680 ALOGE("%s: layer%d: streamon failed %d", __func__
, hl
.id
, errno
);
688 if (acquireFenceFd
>= 0)
689 close(acquireFenceFd
);
694 bool exynos5_is_offscreen(hwc_layer_1_t
&layer
,
695 struct exynos5_hwc_composer_device_1_t
*pdev
)
697 return layer
.sourceCrop
.left
> pdev
->xres
||
698 layer
.sourceCrop
.right
< 0 ||
699 layer
.sourceCrop
.top
> pdev
->yres
||
700 layer
.sourceCrop
.bottom
< 0;
703 size_t exynos5_visible_width(hwc_layer_1_t
&layer
, int format
,
704 struct exynos5_hwc_composer_device_1_t
*pdev
)
707 if (exynos5_requires_gscaler(layer
, format
))
710 bpp
= exynos5_format_to_bpp(format
);
711 int left
= max(layer
.displayFrame
.left
, 0);
712 int right
= min(layer
.displayFrame
.right
, pdev
->xres
);
714 return (right
- left
) * bpp
/ 8;
717 bool exynos5_supports_overlay(hwc_layer_1_t
&layer
, size_t i
,
718 struct exynos5_hwc_composer_device_1_t
*pdev
)
720 if (layer
.flags
& HWC_SKIP_LAYER
) {
721 ALOGV("\tlayer %u: skipping", i
);
725 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
728 ALOGV("\tlayer %u: handle is NULL", i
);
732 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
733 if (!exynos5_supports_gscaler(layer
, handle
->format
, false)) {
734 ALOGV("\tlayer %u: gscaler required but not supported", i
);
738 if (!exynos5_format_is_supported(handle
->format
)) {
739 ALOGV("\tlayer %u: pixel format %u not supported", i
, handle
->format
);
743 if (!exynos5_blending_is_supported(layer
.blending
)) {
744 ALOGV("\tlayer %u: blending %d not supported", i
, layer
.blending
);
747 if (CC_UNLIKELY(exynos5_is_offscreen(layer
, pdev
))) {
748 ALOGW("\tlayer %u: off-screen", i
);
751 if (exynos5_visible_width(layer
, handle
->format
, pdev
) < BURSTLEN_BYTES
) {
752 ALOGV("\tlayer %u: visible area is too narrow", i
);
759 inline bool intersect(const hwc_rect
&r1
, const hwc_rect
&r2
)
761 return !(r1
.left
> r2
.right
||
762 r1
.right
< r2
.left
||
763 r1
.top
> r2
.bottom
||
767 inline hwc_rect
intersection(const hwc_rect
&r1
, const hwc_rect
&r2
)
770 i
.top
= max(r1
.top
, r2
.top
);
771 i
.bottom
= min(r1
.bottom
, r2
.bottom
);
772 i
.left
= max(r1
.left
, r2
.left
);
773 i
.right
= min(r1
.right
, r2
.right
);
777 static int exynos5_prepare_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
778 hwc_display_contents_1_t
* contents
)
780 ALOGV("preparing %u layers for FIMD", contents
->numHwLayers
);
782 memset(pdev
->bufs
.gsc_map
, 0, sizeof(pdev
->bufs
.gsc_map
));
784 bool force_fb
= pdev
->force_gpu
;
785 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
786 pdev
->bufs
.overlay_map
[i
] = -1;
788 bool fb_needed
= false;
789 size_t first_fb
= 0, last_fb
= 0;
791 // find unsupported overlays
792 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
793 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
795 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
796 ALOGV("\tlayer %u: framebuffer target", i
);
800 if (layer
.compositionType
== HWC_BACKGROUND
&& !force_fb
) {
801 ALOGV("\tlayer %u: background supported", i
);
802 dump_layer(&contents
->hwLayers
[i
]);
806 if (exynos5_supports_overlay(contents
->hwLayers
[i
], i
, pdev
) &&
808 ALOGV("\tlayer %u: overlay supported", i
);
809 layer
.compositionType
= HWC_OVERLAY
;
810 dump_layer(&contents
->hwLayers
[i
]);
819 layer
.compositionType
= HWC_FRAMEBUFFER
;
821 dump_layer(&contents
->hwLayers
[i
]);
824 // can't composite overlays sandwiched between framebuffers
826 for (size_t i
= first_fb
; i
< last_fb
; i
++)
827 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
829 // Incrementally try to add our supported layers to hardware windows.
830 // If adding a layer would violate a hardware constraint, force it
831 // into the framebuffer and try again. (Revisiting the entire list is
832 // necessary because adding a layer to the framebuffer can cause other
833 // windows to retroactively violate constraints.)
837 android::Vector
<hwc_rect
> rects
;
838 android::Vector
<hwc_rect
> overlaps
;
839 size_t pixels_left
, windows_left
;
845 fb_rect
.top
= fb_rect
.left
= 0;
846 fb_rect
.right
= pdev
->xres
- 1;
847 fb_rect
.bottom
= pdev
->yres
- 1;
848 pixels_left
= MAX_PIXELS
- pdev
->xres
* pdev
->yres
;
849 windows_left
= NUM_HW_WINDOWS
- 1;
850 rects
.push_back(fb_rect
);
853 pixels_left
= MAX_PIXELS
;
854 windows_left
= NUM_HW_WINDOWS
;
859 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
860 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
861 if ((layer
.flags
& HWC_SKIP_LAYER
) ||
862 layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
)
865 private_handle_t
*handle
= private_handle_t::dynamicCast(
868 // we've already accounted for the framebuffer above
869 if (layer
.compositionType
== HWC_FRAMEBUFFER
)
872 // only layer 0 can be HWC_BACKGROUND, so we can
873 // unconditionally allow it without extra checks
874 if (layer
.compositionType
== HWC_BACKGROUND
) {
879 size_t pixels_needed
= WIDTH(layer
.displayFrame
) *
880 HEIGHT(layer
.displayFrame
);
881 bool can_compose
= windows_left
&& pixels_needed
<= pixels_left
;
882 bool gsc_required
= exynos5_requires_gscaler(layer
, handle
->format
);
884 can_compose
= can_compose
&& !gsc_used
;
886 // hwc_rect_t right and bottom values are normally exclusive;
887 // the intersection logic is simpler if we make them inclusive
888 hwc_rect_t visible_rect
= layer
.displayFrame
;
889 visible_rect
.right
--; visible_rect
.bottom
--;
891 // no more than 2 layers can overlap on a given pixel
892 for (size_t j
= 0; can_compose
&& j
< overlaps
.size(); j
++) {
893 if (intersect(visible_rect
, overlaps
.itemAt(j
)))
898 layer
.compositionType
= HWC_FRAMEBUFFER
;
900 first_fb
= last_fb
= i
;
904 first_fb
= min(i
, first_fb
);
905 last_fb
= max(i
, last_fb
);
911 for (size_t j
= 0; j
< rects
.size(); j
++) {
912 const hwc_rect_t
&other_rect
= rects
.itemAt(j
);
913 if (intersect(visible_rect
, other_rect
))
914 overlaps
.push_back(intersection(visible_rect
, other_rect
));
916 rects
.push_back(visible_rect
);
917 pixels_left
-= pixels_needed
;
924 for (size_t i
= first_fb
; i
< last_fb
; i
++)
925 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
928 unsigned int nextWindow
= 0;
930 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
931 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
933 if (fb_needed
&& i
== first_fb
) {
934 ALOGV("assigning framebuffer to window %u\n",
940 if (layer
.compositionType
!= HWC_FRAMEBUFFER
&&
941 layer
.compositionType
!= HWC_FRAMEBUFFER_TARGET
) {
942 ALOGV("assigning layer %u to window %u", i
, nextWindow
);
943 pdev
->bufs
.overlay_map
[nextWindow
] = i
;
944 if (layer
.compositionType
== HWC_OVERLAY
) {
945 private_handle_t
*handle
=
946 private_handle_t::dynamicCast(layer
.handle
);
947 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
948 ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS
[FIMD_GSC_IDX
]);
949 pdev
->bufs
.gsc_map
[nextWindow
].mode
=
950 exynos5_gsc_map_t::GSC_M2M
;
951 pdev
->bufs
.gsc_map
[nextWindow
].idx
= FIMD_GSC_IDX
;
959 exynos5_cleanup_gsc_m2m(pdev
, FIMD_GSC_IDX
);
962 pdev
->bufs
.fb_window
= first_fb
;
964 pdev
->bufs
.fb_window
= NO_FB_NEEDED
;
969 static int exynos5_prepare_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
970 hwc_display_contents_1_t
* contents
)
972 ALOGV("preparing %u layers for HDMI", contents
->numHwLayers
);
973 hwc_layer_1_t
*video_layer
= NULL
;
975 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
976 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
978 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
979 ALOGV("\tlayer %u: framebuffer target", i
);
983 if (layer
.compositionType
== HWC_BACKGROUND
) {
984 ALOGV("\tlayer %u: background layer", i
);
990 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
991 if (h
->flags
& GRALLOC_USAGE_PROTECTED
) {
993 video_layer
= &layer
;
994 layer
.compositionType
= HWC_OVERLAY
;
995 ALOGV("\tlayer %u: video layer", i
);
1002 layer
.compositionType
= HWC_FRAMEBUFFER
;
1009 static int exynos5_prepare(hwc_composer_device_1_t
*dev
,
1010 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1012 if (!numDisplays
|| !displays
)
1015 exynos5_hwc_composer_device_1_t
*pdev
=
1016 (exynos5_hwc_composer_device_1_t
*)dev
;
1017 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1018 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1020 if (pdev
->hdmi_hpd
) {
1026 if (fimd_contents
) {
1027 int err
= exynos5_prepare_fimd(pdev
, fimd_contents
);
1032 if (hdmi_contents
) {
1033 int err
= exynos5_prepare_hdmi(pdev
, hdmi_contents
);
1041 static int exynos5_config_gsc_m2m(hwc_layer_1_t
&layer
,
1042 alloc_device_t
* alloc_device
, exynos5_gsc_data_t
*gsc_data
,
1043 int gsc_idx
, int dst_format
)
1045 ALOGV("configuring gscaler %u for memory-to-memory", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1047 private_handle_t
*src_handle
= private_handle_t::dynamicCast(layer
.handle
);
1048 buffer_handle_t dst_buf
;
1049 private_handle_t
*dst_handle
;
1052 exynos_gsc_img src_cfg
, dst_cfg
;
1053 memset(&src_cfg
, 0, sizeof(src_cfg
));
1054 memset(&dst_cfg
, 0, sizeof(dst_cfg
));
1056 src_cfg
.x
= layer
.sourceCrop
.left
;
1057 src_cfg
.y
= layer
.sourceCrop
.top
;
1058 src_cfg
.w
= WIDTH(layer
.sourceCrop
);
1059 src_cfg
.fw
= src_handle
->stride
;
1060 src_cfg
.h
= HEIGHT(layer
.sourceCrop
);
1061 src_cfg
.fh
= src_handle
->vstride
;
1062 src_cfg
.yaddr
= src_handle
->fd
;
1063 if (exynos5_format_is_ycrcb(src_handle
->format
)) {
1064 src_cfg
.uaddr
= src_handle
->fd2
;
1065 src_cfg
.vaddr
= src_handle
->fd1
;
1067 src_cfg
.uaddr
= src_handle
->fd1
;
1068 src_cfg
.vaddr
= src_handle
->fd2
;
1070 src_cfg
.format
= src_handle
->format
;
1071 src_cfg
.drmMode
= !!(src_handle
->flags
& GRALLOC_USAGE_PROTECTED
);
1072 src_cfg
.acquireFenceFd
= layer
.acquireFenceFd
;
1073 layer
.acquireFenceFd
= -1;
1077 dst_cfg
.w
= WIDTH(layer
.displayFrame
);
1078 dst_cfg
.h
= HEIGHT(layer
.displayFrame
);
1079 dst_cfg
.rot
= layer
.transform
;
1080 dst_cfg
.drmMode
= src_cfg
.drmMode
;
1081 dst_cfg
.format
= dst_format
;
1082 dst_cfg
.acquireFenceFd
= -1;
1084 ALOGV("source configuration:");
1085 dump_gsc_img(src_cfg
);
1087 bool reconfigure
= gsc_src_cfg_changed(src_cfg
, gsc_data
->src_cfg
) ||
1088 gsc_dst_cfg_changed(dst_cfg
, gsc_data
->dst_cfg
);
1091 int usage
= GRALLOC_USAGE_SW_READ_NEVER
|
1092 GRALLOC_USAGE_SW_WRITE_NEVER
|
1093 GRALLOC_USAGE_HW_COMPOSER
;
1095 if (src_handle
->flags
& GRALLOC_USAGE_PROTECTED
)
1096 usage
|= GRALLOC_USAGE_PROTECTED
;
1098 int w
= ALIGN(WIDTH(layer
.displayFrame
), GSC_DST_W_ALIGNMENT_RGB888
);
1099 int h
= ALIGN(HEIGHT(layer
.displayFrame
), GSC_DST_H_ALIGNMENT_RGB888
);
1101 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1102 if (gsc_data
->dst_buf
[i
]) {
1103 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1104 gsc_data
->dst_buf
[i
] = NULL
;
1107 int ret
= alloc_device
->alloc(alloc_device
, w
, h
,
1108 HAL_PIXEL_FORMAT_RGBX_8888
, usage
, &gsc_data
->dst_buf
[i
],
1111 ALOGE("failed to allocate destination buffer: %s",
1117 gsc_data
->current_buf
= 0;
1120 dst_buf
= gsc_data
->dst_buf
[gsc_data
->current_buf
];
1121 dst_handle
= private_handle_t::dynamicCast(dst_buf
);
1123 dst_cfg
.fw
= dst_handle
->stride
;
1124 dst_cfg
.fh
= dst_handle
->vstride
;
1125 dst_cfg
.yaddr
= dst_handle
->fd
;
1127 ALOGV("destination configuration:");
1128 dump_gsc_img(dst_cfg
);
1130 if (gsc_data
->gsc
) {
1131 ALOGV("reusing open gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1133 ALOGV("opening gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1134 gsc_data
->gsc
= exynos_gsc_create_exclusive(
1135 AVAILABLE_GSC_UNITS
[gsc_idx
], GSC_M2M_MODE
, GSC_DUMMY
, true);
1136 if (!gsc_data
->gsc
) {
1137 ALOGE("failed to create gscaler handle");
1144 ret
= exynos_gsc_stop_exclusive(gsc_data
->gsc
);
1146 ALOGE("failed to stop gscaler %u", gsc_idx
);
1147 goto err_gsc_config
;
1150 ret
= exynos_gsc_config_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1152 ALOGE("failed to configure gscaler %u", gsc_idx
);
1153 goto err_gsc_config
;
1157 ret
= exynos_gsc_run_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1159 ALOGE("failed to run gscaler %u", gsc_idx
);
1160 goto err_gsc_config
;
1163 gsc_data
->src_cfg
= src_cfg
;
1164 gsc_data
->dst_cfg
= dst_cfg
;
1166 layer
.releaseFenceFd
= src_cfg
.releaseFenceFd
;
1171 exynos_gsc_destroy(gsc_data
->gsc
);
1172 gsc_data
->gsc
= NULL
;
1174 if (src_cfg
.acquireFenceFd
>= 0)
1175 close(src_cfg
.acquireFenceFd
);
1176 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1177 if (gsc_data
->dst_buf
[i
]) {
1178 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1179 gsc_data
->dst_buf
[i
] = NULL
;
1182 memset(&gsc_data
->src_cfg
, 0, sizeof(gsc_data
->src_cfg
));
1183 memset(&gsc_data
->dst_cfg
, 0, sizeof(gsc_data
->dst_cfg
));
1188 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
1191 exynos5_gsc_data_t
&gsc_data
= pdev
->gsc
[gsc_idx
];
1195 ALOGV("closing gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1197 exynos_gsc_stop_exclusive(gsc_data
.gsc
);
1198 exynos_gsc_destroy(gsc_data
.gsc
);
1199 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++)
1200 if (gsc_data
.dst_buf
[i
])
1201 pdev
->alloc_device
->free(pdev
->alloc_device
, gsc_data
.dst_buf
[i
]);
1203 memset(&gsc_data
, 0, sizeof(gsc_data
));
1206 static void exynos5_config_handle(private_handle_t
*handle
,
1207 hwc_rect_t
&sourceCrop
, hwc_rect_t
&displayFrame
,
1208 int32_t blending
, int fence_fd
, s3c_fb_win_config
&cfg
,
1209 exynos5_hwc_composer_device_1_t
*pdev
)
1212 uint32_t w
= WIDTH(displayFrame
);
1213 uint32_t h
= HEIGHT(displayFrame
);
1214 uint8_t bpp
= exynos5_format_to_bpp(handle
->format
);
1215 uint32_t offset
= (sourceCrop
.top
* handle
->stride
+ sourceCrop
.left
) * bpp
/ 8;
1217 if (displayFrame
.left
< 0) {
1218 unsigned int crop
= -displayFrame
.left
;
1219 ALOGV("layer off left side of screen; cropping %u pixels from left edge",
1223 offset
+= crop
* bpp
/ 8;
1225 x
= displayFrame
.left
;
1228 if (displayFrame
.right
> pdev
->xres
) {
1229 unsigned int crop
= displayFrame
.right
- pdev
->xres
;
1230 ALOGV("layer off right side of screen; cropping %u pixels from right edge",
1235 if (displayFrame
.top
< 0) {
1236 unsigned int crop
= -displayFrame
.top
;
1237 ALOGV("layer off top side of screen; cropping %u pixels from top edge",
1241 offset
+= handle
->stride
* crop
* bpp
/ 8;
1243 y
= displayFrame
.top
;
1246 if (displayFrame
.bottom
> pdev
->yres
) {
1247 int crop
= displayFrame
.bottom
- pdev
->yres
;
1248 ALOGV("layer off bottom side of screen; cropping %u pixels from bottom edge",
1253 cfg
.state
= cfg
.S3C_FB_WIN_STATE_BUFFER
;
1254 cfg
.fd
= handle
->fd
;
1259 cfg
.format
= exynos5_format_to_s3c_format(handle
->format
);
1260 cfg
.offset
= offset
;
1261 cfg
.stride
= handle
->stride
* bpp
/ 8;
1262 cfg
.blending
= exynos5_blending_to_s3c_blending(blending
);
1263 cfg
.fence_fd
= fence_fd
;
1266 static void exynos5_config_overlay(hwc_layer_1_t
*layer
, s3c_fb_win_config
&cfg
,
1267 exynos5_hwc_composer_device_1_t
*pdev
)
1269 if (layer
->compositionType
== HWC_BACKGROUND
) {
1270 hwc_color_t color
= layer
->backgroundColor
;
1271 cfg
.state
= cfg
.S3C_FB_WIN_STATE_COLOR
;
1272 cfg
.color
= (color
.r
<< 16) | (color
.g
<< 8) | color
.b
;
1280 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
->handle
);
1281 exynos5_config_handle(handle
, layer
->sourceCrop
, layer
->displayFrame
,
1282 layer
->blending
, layer
->acquireFenceFd
, cfg
, pdev
);
1285 static int exynos5_post_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1286 hwc_display_contents_1_t
* contents
)
1288 exynos5_hwc_post_data_t
*pdata
= &pdev
->bufs
;
1289 struct s3c_fb_win_config_data win_data
;
1290 struct s3c_fb_win_config
*config
= win_data
.config
;
1292 memset(config
, 0, sizeof(win_data
.config
));
1293 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1294 config
[i
].fence_fd
= -1;
1296 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1297 int layer_idx
= pdata
->overlay_map
[i
];
1298 if (layer_idx
!= -1) {
1299 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1300 private_handle_t
*handle
=
1301 private_handle_t::dynamicCast(layer
.handle
);
1303 if (pdata
->gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1304 int gsc_idx
= pdata
->gsc_map
[i
].idx
;
1305 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1307 // RGBX8888 surfaces are already in the right color order from the GPU,
1308 // RGB565 and YUV surfaces need the Gscaler to swap R & B
1309 int dst_format
= HAL_PIXEL_FORMAT_BGRA_8888
;
1310 if (exynos5_format_is_rgb(handle
->format
) &&
1311 handle
->format
!= HAL_PIXEL_FORMAT_RGB_565
)
1312 dst_format
= HAL_PIXEL_FORMAT_RGBX_8888
;
1314 int err
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
,
1315 gsc_idx
, dst_format
);
1317 ALOGE("failed to configure gscaler %u for layer %u",
1322 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1323 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1324 private_handle_t
*dst_handle
=
1325 private_handle_t::dynamicCast(dst_buf
);
1326 hwc_rect_t sourceCrop
= { 0, 0,
1327 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
) };
1328 int fence
= gsc
.dst_cfg
.releaseFenceFd
;
1329 exynos5_config_handle(dst_handle
, sourceCrop
,
1330 layer
.displayFrame
, layer
.blending
, fence
, config
[i
],
1333 exynos5_config_overlay(&layer
, config
[i
], pdev
);
1336 if (i
== 0 && config
[i
].blending
!= S3C_FB_BLENDING_NONE
) {
1337 ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
1338 config
[i
].blending
= S3C_FB_BLENDING_NONE
;
1341 ALOGV("window %u configuration:", i
);
1342 dump_config(config
[i
]);
1345 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1346 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1347 if (config
[i
].fence_fd
!= -1)
1348 close(config
[i
].fence_fd
);
1350 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %s", strerror(errno
));
1354 memcpy(pdev
->last_config
, &win_data
.config
, sizeof(win_data
.config
));
1355 memcpy(pdev
->last_gsc_map
, pdata
->gsc_map
, sizeof(pdata
->gsc_map
));
1356 pdev
->last_fb_window
= pdata
->fb_window
;
1357 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1358 int layer_idx
= pdata
->overlay_map
[i
];
1359 if (layer_idx
!= -1) {
1360 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1361 pdev
->last_handles
[i
] = layer
.handle
;
1365 return win_data
.fence
;
1368 static int exynos5_clear_fimd(exynos5_hwc_composer_device_1_t
*pdev
)
1370 struct s3c_fb_win_config_data win_data
;
1371 memset(&win_data
, 0, sizeof(win_data
));
1373 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1374 LOG_ALWAYS_FATAL_IF(ret
< 0,
1375 "ioctl S3CFB_WIN_CONFIG failed to clear screen: %s",
1377 // the causes of an empty config failing are all unrecoverable
1379 return win_data
.fence
;
1382 static int exynos5_set_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1383 hwc_display_contents_1_t
* contents
)
1385 if (!contents
->dpy
|| !contents
->sur
)
1388 hwc_layer_1_t
*fb_layer
= NULL
;
1391 if (pdev
->bufs
.fb_window
!= NO_FB_NEEDED
) {
1392 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1393 if (contents
->hwLayers
[i
].compositionType
==
1394 HWC_FRAMEBUFFER_TARGET
) {
1395 pdev
->bufs
.overlay_map
[pdev
->bufs
.fb_window
] = i
;
1396 fb_layer
= &contents
->hwLayers
[i
];
1401 if (CC_UNLIKELY(!fb_layer
)) {
1402 ALOGE("framebuffer target expected, but not provided");
1405 ALOGV("framebuffer target buffer:");
1406 dump_layer(fb_layer
);
1412 fence
= exynos5_post_fimd(pdev
, contents
);
1418 fence
= exynos5_clear_fimd(pdev
);
1420 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1421 if (pdev
->bufs
.overlay_map
[i
] != -1 &&
1422 pdev
->bufs
.gsc_map
[i
].mode
!= exynos5_gsc_map_t::GSC_M2M
) {
1423 hwc_layer_1_t
&layer
=
1424 contents
->hwLayers
[pdev
->bufs
.overlay_map
[i
]];
1425 int dup_fd
= dup(fence
);
1427 ALOGW("release fence dup failed: %s", strerror(errno
));
1428 layer
.releaseFenceFd
= dup_fd
;
1436 static int exynos5_set_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1437 hwc_display_contents_1_t
* contents
)
1439 hwc_layer_1_t
*fb_layer
= NULL
;
1440 hwc_layer_1_t
*video_layer
= NULL
;
1442 if (!pdev
->hdmi_enabled
) {
1443 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1444 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1445 if (layer
.acquireFenceFd
!= -1) {
1446 close(layer
.acquireFenceFd
);
1447 layer
.acquireFenceFd
= -1;
1453 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1454 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1456 if (layer
.flags
& HWC_SKIP_LAYER
) {
1457 ALOGV("HDMI skipping layer %d", i
);
1461 if (layer
.compositionType
== HWC_OVERLAY
) {
1465 ALOGV("HDMI video layer:");
1468 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[HDMI_GSC_IDX
];
1469 int ret
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
, 1,
1470 HAL_PIXEL_FORMAT_RGBX_8888
);
1472 ALOGE("failed to configure gscaler for video layer");
1476 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1477 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1478 private_handle_t
*h
= private_handle_t::dynamicCast(dst_buf
);
1480 int acquireFenceFd
= gsc
.dst_cfg
.releaseFenceFd
;
1482 hdmi_output(pdev
, pdev
->hdmi_layers
[0], layer
, h
, acquireFenceFd
, NULL
);
1483 video_layer
= &layer
;
1486 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1490 ALOGV("HDMI FB layer:");
1493 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1494 hdmi_output(pdev
, pdev
->hdmi_layers
[1], layer
, h
, layer
.acquireFenceFd
,
1495 &layer
.releaseFenceFd
);
1501 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[0]);
1502 exynos5_cleanup_gsc_m2m(pdev
, HDMI_GSC_IDX
);
1505 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[1]);
1510 static int exynos5_set(struct hwc_composer_device_1
*dev
,
1511 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1513 if (!numDisplays
|| !displays
)
1516 exynos5_hwc_composer_device_1_t
*pdev
=
1517 (exynos5_hwc_composer_device_1_t
*)dev
;
1518 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1519 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1520 int fimd_err
= 0, hdmi_err
= 0;
1523 fimd_err
= exynos5_set_fimd(pdev
, fimd_contents
);
1526 hdmi_err
= exynos5_set_hdmi(pdev
, hdmi_contents
);
1534 static void exynos5_registerProcs(struct hwc_composer_device_1
* dev
,
1535 hwc_procs_t
const* procs
)
1537 struct exynos5_hwc_composer_device_1_t
* pdev
=
1538 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1539 pdev
->procs
= procs
;
1542 static int exynos5_query(struct hwc_composer_device_1
* dev
, int what
, int *value
)
1544 struct exynos5_hwc_composer_device_1_t
*pdev
=
1545 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1548 case HWC_BACKGROUND_LAYER_SUPPORTED
:
1549 // we support the background layer
1552 case HWC_VSYNC_PERIOD
:
1553 // vsync period in nanosecond
1554 value
[0] = pdev
->vsync_period
;
1557 // unsupported query
1563 static int exynos5_eventControl(struct hwc_composer_device_1
*dev
, int dpy
,
1564 int event
, int enabled
)
1566 struct exynos5_hwc_composer_device_1_t
*pdev
=
1567 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1570 case HWC_EVENT_VSYNC
:
1571 __u32 val
= !!enabled
;
1572 int err
= ioctl(pdev
->fd
, S3CFB_SET_VSYNC_INT
, &val
);
1574 ALOGE("vsync ioctl failed");
1584 static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t
*pdev
,
1585 const char *buff
, int len
)
1587 const char *s
= buff
;
1591 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1592 pdev
->hdmi_hpd
= atoi(s
+ strlen("SWITCH_STATE=")) == 1;
1595 if (s
- buff
>= len
)
1599 if (pdev
->hdmi_hpd
) {
1600 if (hdmi_get_config(pdev
)) {
1601 ALOGE("Error reading HDMI configuration");
1602 pdev
->hdmi_hpd
= false;
1606 pdev
->hdmi_blanked
= false;
1609 ALOGV("HDMI HPD changed to %s", pdev
->hdmi_hpd
? "enabled" : "disabled");
1611 ALOGI("HDMI Resolution changed to %dx%d", pdev
->hdmi_h
, pdev
->hdmi_w
);
1613 /* hwc_dev->procs is set right after the device is opened, but there is
1614 * still a race condition where a hotplug event might occur after the open
1615 * but before the procs are registered. */
1617 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, pdev
->hdmi_hpd
);
1620 static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t
*pdev
)
1625 int err
= lseek(pdev
->vsync_fd
, 0, SEEK_SET
);
1627 ALOGE("error seeking to vsync timestamp: %s", strerror(errno
));
1632 err
= read(pdev
->vsync_fd
, buf
, sizeof(buf
));
1634 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1637 buf
[sizeof(buf
) - 1] = '\0';
1640 uint64_t timestamp
= strtoull(buf
, NULL
, 0);
1642 pdev
->procs
->vsync(pdev
->procs
, 0, timestamp
);
1645 static void *hwc_vsync_thread(void *data
)
1647 struct exynos5_hwc_composer_device_1_t
*pdev
=
1648 (struct exynos5_hwc_composer_device_1_t
*)data
;
1649 char uevent_desc
[4096];
1650 memset(uevent_desc
, 0, sizeof(uevent_desc
));
1652 setpriority(PRIO_PROCESS
, 0, HAL_PRIORITY_URGENT_DISPLAY
);
1657 int err
= read(pdev
->vsync_fd
, temp
, sizeof(temp
));
1659 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1663 struct pollfd fds
[2];
1664 fds
[0].fd
= pdev
->vsync_fd
;
1665 fds
[0].events
= POLLPRI
;
1666 fds
[1].fd
= uevent_get_fd();
1667 fds
[1].events
= POLLIN
;
1670 int err
= poll(fds
, 2, -1);
1673 if (fds
[0].revents
& POLLPRI
) {
1674 handle_vsync_event(pdev
);
1676 else if (fds
[1].revents
& POLLIN
) {
1677 int len
= uevent_next_event(uevent_desc
,
1678 sizeof(uevent_desc
) - 2);
1680 bool hdmi
= !strcmp(uevent_desc
,
1681 "change@/devices/virtual/switch/hdmi");
1683 handle_hdmi_uevent(pdev
, uevent_desc
, len
);
1686 else if (err
== -1) {
1689 ALOGE("error in vsync thread: %s", strerror(errno
));
1696 static int exynos5_blank(struct hwc_composer_device_1
*dev
, int disp
, int blank
)
1698 struct exynos5_hwc_composer_device_1_t
*pdev
=
1699 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1702 case HWC_DISPLAY_PRIMARY
: {
1703 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
1704 int err
= ioctl(pdev
->fd
, FBIOBLANK
, fb_blank
);
1707 ALOGI("%sblank ioctl failed (display already %sblanked)",
1708 blank
? "" : "un", blank
? "" : "un");
1710 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
1717 case HWC_DISPLAY_EXTERNAL
:
1718 if (pdev
->hdmi_hpd
) {
1719 if (blank
&& !pdev
->hdmi_blanked
)
1721 pdev
->hdmi_blanked
= !!blank
;
1733 static void exynos5_dump(hwc_composer_device_1
* dev
, char *buff
, int buff_len
)
1738 struct exynos5_hwc_composer_device_1_t
*pdev
=
1739 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1741 android::String8 result
;
1743 result
.appendFormat(" hdmi_enabled=%u\n", pdev
->hdmi_enabled
);
1744 if (pdev
->hdmi_enabled
)
1745 result
.appendFormat(" w=%u, h=%u\n", pdev
->hdmi_w
, pdev
->hdmi_h
);
1747 " type | handle | color | blend | format | position | size | gsc \n"
1748 "----------+----------|----------+-------+--------+---------------+---------------------\n");
1749 // 8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
1751 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1752 struct s3c_fb_win_config
&config
= pdev
->last_config
[i
];
1753 if (config
.state
== config
.S3C_FB_WIN_STATE_DISABLED
) {
1754 result
.appendFormat(" %8s | %8s | %8s | %5s | %6s | %13s | %13s",
1755 "DISABLED", "-", "-", "-", "-", "-", "-");
1758 if (config
.state
== config
.S3C_FB_WIN_STATE_COLOR
)
1759 result
.appendFormat(" %8s | %8s | %8x | %5s | %6s", "COLOR",
1760 "-", config
.color
, "-", "-");
1762 result
.appendFormat(" %8s | %8x | %8s | %5x | %6x",
1763 pdev
->last_fb_window
== i
? "FB" : "OVERLAY",
1764 intptr_t(pdev
->last_handles
[i
]),
1765 "-", config
.blending
, config
.format
);
1767 result
.appendFormat(" | [%5d,%5d] | [%5u,%5u]", config
.x
, config
.y
,
1768 config
.w
, config
.h
);
1770 if (pdev
->last_gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_NONE
)
1771 result
.appendFormat(" | %3s", "-");
1773 result
.appendFormat(" | %3d",
1774 AVAILABLE_GSC_UNITS
[pdev
->last_gsc_map
[i
].idx
]);
1775 result
.append("\n");
1778 strlcpy(buff
, result
.string(), buff_len
);
1781 static int exynos5_getDisplayConfigs(struct hwc_composer_device_1
*dev
,
1782 int disp
, uint32_t *configs
, size_t *numConfigs
)
1784 struct exynos5_hwc_composer_device_1_t
*pdev
=
1785 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1787 if (*numConfigs
== 0)
1790 if (disp
== HWC_DISPLAY_PRIMARY
) {
1794 } else if (disp
== HWC_DISPLAY_EXTERNAL
) {
1795 if (!pdev
->hdmi_hpd
) {
1799 int err
= hdmi_get_config(pdev
);
1812 static int32_t exynos5_fimd_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1813 const uint32_t attribute
)
1816 case HWC_DISPLAY_VSYNC_PERIOD
:
1817 return pdev
->vsync_period
;
1819 case HWC_DISPLAY_WIDTH
:
1822 case HWC_DISPLAY_HEIGHT
:
1825 case HWC_DISPLAY_DPI_X
:
1828 case HWC_DISPLAY_DPI_Y
:
1832 ALOGE("unknown display attribute %u", attribute
);
1837 static int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1838 const uint32_t attribute
)
1841 case HWC_DISPLAY_VSYNC_PERIOD
:
1842 return pdev
->vsync_period
;
1844 case HWC_DISPLAY_WIDTH
:
1845 return pdev
->hdmi_w
;
1847 case HWC_DISPLAY_HEIGHT
:
1848 return pdev
->hdmi_h
;
1850 case HWC_DISPLAY_DPI_X
:
1851 case HWC_DISPLAY_DPI_Y
:
1852 return 0; // unknown
1855 ALOGE("unknown display attribute %u", attribute
);
1860 static int exynos5_getDisplayAttributes(struct hwc_composer_device_1
*dev
,
1861 int disp
, uint32_t config
, const uint32_t *attributes
, int32_t *values
)
1863 struct exynos5_hwc_composer_device_1_t
*pdev
=
1864 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1866 for (int i
= 0; attributes
[i
] != HWC_DISPLAY_NO_ATTRIBUTE
; i
++) {
1867 if (disp
== HWC_DISPLAY_PRIMARY
)
1868 values
[i
] = exynos5_fimd_attribute(pdev
, attributes
[i
]);
1869 else if (disp
== HWC_DISPLAY_EXTERNAL
)
1870 values
[i
] = exynos5_hdmi_attribute(pdev
, attributes
[i
]);
1872 ALOGE("unknown display type %u", disp
);
1880 static int exynos5_close(hw_device_t
* device
);
1882 static int exynos5_open(const struct hw_module_t
*module
, const char *name
,
1883 struct hw_device_t
**device
)
1889 if (strcmp(name
, HWC_HARDWARE_COMPOSER
)) {
1893 struct exynos5_hwc_composer_device_1_t
*dev
;
1894 dev
= (struct exynos5_hwc_composer_device_1_t
*)malloc(sizeof(*dev
));
1895 memset(dev
, 0, sizeof(*dev
));
1897 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
,
1898 (const struct hw_module_t
**)&dev
->gralloc_module
)) {
1899 ALOGE("failed to get gralloc hw module");
1901 goto err_get_module
;
1904 if (gralloc_open((const hw_module_t
*)dev
->gralloc_module
,
1905 &dev
->alloc_device
)) {
1906 ALOGE("failed to open gralloc");
1908 goto err_get_module
;
1911 dev
->fd
= open("/dev/graphics/fb0", O_RDWR
);
1913 ALOGE("failed to open framebuffer");
1918 struct fb_var_screeninfo info
;
1919 if (ioctl(dev
->fd
, FBIOGET_VSCREENINFO
, &info
) == -1) {
1920 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno
));
1925 refreshRate
= 1000000000000LLU /
1927 uint64_t( info
.upper_margin
+ info
.lower_margin
+ info
.yres
)
1928 * ( info
.left_margin
+ info
.right_margin
+ info
.xres
)
1932 if (refreshRate
== 0) {
1933 ALOGW("invalid refresh rate, assuming 60 Hz");
1939 dev
->xdpi
= 1000 * (info
.xres
* 25.4f
) / info
.width
;
1940 dev
->ydpi
= 1000 * (info
.yres
* 25.4f
) / info
.height
;
1941 dev
->vsync_period
= 1000000000 / refreshRate
;
1946 "width = %d mm (%f dpi)\n"
1947 "height = %d mm (%f dpi)\n"
1948 "refresh rate = %d Hz\n",
1949 dev
->xres
, dev
->yres
, info
.width
, dev
->xdpi
/ 1000.0,
1950 info
.height
, dev
->ydpi
/ 1000.0, refreshRate
);
1952 dev
->hdmi_mixer0
= open("/dev/v4l-subdev7", O_RDWR
);
1953 if (dev
->hdmi_mixer0
< 0) {
1954 ALOGE("failed to open hdmi mixer0 subdev");
1955 ret
= dev
->hdmi_mixer0
;
1959 dev
->hdmi_layers
[0].id
= 0;
1960 dev
->hdmi_layers
[0].fd
= open("/dev/video16", O_RDWR
);
1961 if (dev
->hdmi_layers
[0].fd
< 0) {
1962 ALOGE("failed to open hdmi layer0 device");
1963 ret
= dev
->hdmi_layers
[0].fd
;
1967 dev
->hdmi_layers
[1].id
= 1;
1968 dev
->hdmi_layers
[1].fd
= open("/dev/video17", O_RDWR
);
1969 if (dev
->hdmi_layers
[1].fd
< 0) {
1970 ALOGE("failed to open hdmi layer1 device");
1971 ret
= dev
->hdmi_layers
[1].fd
;
1975 dev
->vsync_fd
= open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY
);
1976 if (dev
->vsync_fd
< 0) {
1977 ALOGE("failed to open vsync attribute");
1978 ret
= dev
->vsync_fd
;
1982 sw_fd
= open("/sys/class/switch/hdmi/state", O_RDONLY
);
1985 if (read(sw_fd
, &val
, 1) == 1 && val
== '1') {
1986 dev
->hdmi_hpd
= true;
1987 if (hdmi_get_config(dev
)) {
1988 ALOGE("Error reading HDMI configuration");
1989 dev
->hdmi_hpd
= false;
1994 dev
->base
.common
.tag
= HARDWARE_DEVICE_TAG
;
1995 dev
->base
.common
.version
= HWC_DEVICE_API_VERSION_1_1
;
1996 dev
->base
.common
.module
= const_cast<hw_module_t
*>(module
);
1997 dev
->base
.common
.close
= exynos5_close
;
1999 dev
->base
.prepare
= exynos5_prepare
;
2000 dev
->base
.set
= exynos5_set
;
2001 dev
->base
.eventControl
= exynos5_eventControl
;
2002 dev
->base
.blank
= exynos5_blank
;
2003 dev
->base
.query
= exynos5_query
;
2004 dev
->base
.registerProcs
= exynos5_registerProcs
;
2005 dev
->base
.dump
= exynos5_dump
;
2006 dev
->base
.getDisplayConfigs
= exynos5_getDisplayConfigs
;
2007 dev
->base
.getDisplayAttributes
= exynos5_getDisplayAttributes
;
2009 *device
= &dev
->base
.common
;
2011 ret
= pthread_create(&dev
->vsync_thread
, NULL
, hwc_vsync_thread
, dev
);
2013 ALOGE("failed to start vsync thread: %s", strerror(ret
));
2018 char value
[PROPERTY_VALUE_MAX
];
2019 property_get("debug.hwc.force_gpu", value
, "0");
2020 dev
->force_gpu
= atoi(value
);
2025 close(dev
->vsync_fd
);
2027 close(dev
->hdmi_mixer0
);
2029 close(dev
->hdmi_layers
[0].fd
);
2031 close(dev
->hdmi_layers
[1].fd
);
2035 gralloc_close(dev
->alloc_device
);
2041 static int exynos5_close(hw_device_t
*device
)
2043 struct exynos5_hwc_composer_device_1_t
*dev
=
2044 (struct exynos5_hwc_composer_device_1_t
*)device
;
2045 pthread_kill(dev
->vsync_thread
, SIGTERM
);
2046 pthread_join(dev
->vsync_thread
, NULL
);
2047 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2048 exynos5_cleanup_gsc_m2m(dev
, i
);
2049 gralloc_close(dev
->alloc_device
);
2050 close(dev
->vsync_fd
);
2051 close(dev
->hdmi_mixer0
);
2052 close(dev
->hdmi_layers
[0].fd
);
2053 close(dev
->hdmi_layers
[1].fd
);
2058 static struct hw_module_methods_t exynos5_hwc_module_methods
= {
2062 hwc_module_t HAL_MODULE_INFO_SYM
= {
2064 tag
: HARDWARE_MODULE_TAG
,
2065 module_api_version
: HWC_MODULE_API_VERSION_0_1
,
2066 hal_api_version
: HARDWARE_HAL_API_VERSION
,
2067 id
: HWC_HARDWARE_MODULE_ID
,
2068 name
: "Samsung exynos5 hwcomposer module",
2070 methods
: &exynos5_hwc_module_methods
,