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
];
91 int dst_buf_fence
[NUM_GSC_DST_BUFS
];
106 struct exynos5_hwc_composer_device_1_t
{
107 hwc_composer_device_1_t base
;
111 exynos5_hwc_post_data_t bufs
;
113 const private_module_t
*gralloc_module
;
114 alloc_device_t
*alloc_device
;
115 const hwc_procs_t
*procs
;
116 pthread_t vsync_thread
;
123 int32_t vsync_period
;
132 hdmi_layer_t hdmi_layers
[2];
134 exynos5_gsc_data_t gsc
[NUM_GSC_UNITS
];
136 struct s3c_fb_win_config last_config
[NUM_HW_WINDOWS
];
137 size_t last_fb_window
;
138 const void *last_handles
[NUM_HW_WINDOWS
];
139 exynos5_gsc_map_t last_gsc_map
[NUM_HW_WINDOWS
];
142 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
145 static void dump_handle(private_handle_t
*h
)
147 ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
148 h
->format
, h
->width
, h
->height
, h
->stride
, h
->vstride
);
151 static void dump_layer(hwc_layer_1_t
const *l
)
153 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
154 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
155 l
->compositionType
, l
->flags
, l
->handle
, l
->transform
,
160 l
->sourceCrop
.bottom
,
161 l
->displayFrame
.left
,
163 l
->displayFrame
.right
,
164 l
->displayFrame
.bottom
);
166 if(l
->handle
&& !(l
->flags
& HWC_SKIP_LAYER
))
167 dump_handle(private_handle_t::dynamicCast(l
->handle
));
170 static void dump_config(s3c_fb_win_config
&c
)
172 ALOGV("\tstate = %u", c
.state
);
173 if (c
.state
== c
.S3C_FB_WIN_STATE_BUFFER
) {
174 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
175 "x = %d, y = %d, w = %u, h = %u, "
176 "format = %u, blending = %u",
177 c
.fd
, c
.offset
, c
.stride
,
179 c
.format
, c
.blending
);
181 else if (c
.state
== c
.S3C_FB_WIN_STATE_COLOR
) {
182 ALOGV("\t\tcolor = %u", c
.color
);
186 static void dump_gsc_img(exynos_gsc_img
&c
)
188 ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
189 c
.x
, c
.y
, c
.w
, c
.h
, c
.fw
, c
.fh
);
190 ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
191 c
.yaddr
, c
.uaddr
, c
.vaddr
, c
.rot
, c
.cacheable
, c
.drmMode
);
194 inline int WIDTH(const hwc_rect
&rect
) { return rect
.right
- rect
.left
; }
195 inline int HEIGHT(const hwc_rect
&rect
) { return rect
.bottom
- rect
.top
; }
196 template<typename T
> inline T
max(T a
, T b
) { return (a
> b
) ? a
: b
; }
197 template<typename T
> inline T
min(T a
, T b
) { return (a
< b
) ? a
: b
; }
199 static bool is_transformed(const hwc_layer_1_t
&layer
)
201 return layer
.transform
!= 0;
204 static bool is_rotated(const hwc_layer_1_t
&layer
)
206 return (layer
.transform
& HAL_TRANSFORM_ROT_90
) ||
207 (layer
.transform
& HAL_TRANSFORM_ROT_180
);
210 static bool is_scaled(const hwc_layer_1_t
&layer
)
212 return WIDTH(layer
.displayFrame
) != WIDTH(layer
.sourceCrop
) ||
213 HEIGHT(layer
.displayFrame
) != HEIGHT(layer
.sourceCrop
);
216 static inline bool gsc_dst_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
218 return c1
.x
!= c2
.x
||
222 c1
.format
!= c2
.format
||
224 c1
.cacheable
!= c2
.cacheable
||
225 c1
.drmMode
!= c2
.drmMode
;
228 static inline bool gsc_src_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
230 return gsc_dst_cfg_changed(c1
, c2
) ||
235 static enum s3c_fb_pixel_format
exynos5_format_to_s3c_format(int format
)
238 case HAL_PIXEL_FORMAT_RGBA_8888
:
239 return S3C_FB_PIXEL_FORMAT_RGBA_8888
;
240 case HAL_PIXEL_FORMAT_RGBX_8888
:
241 return S3C_FB_PIXEL_FORMAT_RGBX_8888
;
242 case HAL_PIXEL_FORMAT_RGBA_5551
:
243 return S3C_FB_PIXEL_FORMAT_RGBA_5551
;
244 case HAL_PIXEL_FORMAT_RGB_565
:
245 return S3C_FB_PIXEL_FORMAT_RGB_565
;
246 case HAL_PIXEL_FORMAT_BGRA_8888
:
247 return S3C_FB_PIXEL_FORMAT_BGRA_8888
;
249 return S3C_FB_PIXEL_FORMAT_MAX
;
253 static bool exynos5_format_is_supported(int format
)
255 return exynos5_format_to_s3c_format(format
) < S3C_FB_PIXEL_FORMAT_MAX
;
258 static bool exynos5_format_is_rgb(int format
)
261 case HAL_PIXEL_FORMAT_RGBA_8888
:
262 case HAL_PIXEL_FORMAT_RGBX_8888
:
263 case HAL_PIXEL_FORMAT_RGB_888
:
264 case HAL_PIXEL_FORMAT_RGB_565
:
265 case HAL_PIXEL_FORMAT_BGRA_8888
:
266 case HAL_PIXEL_FORMAT_RGBA_5551
:
267 case HAL_PIXEL_FORMAT_RGBA_4444
:
275 static bool exynos5_format_is_supported_by_gscaler(int format
)
278 case HAL_PIXEL_FORMAT_RGBX_8888
:
279 case HAL_PIXEL_FORMAT_RGB_565
:
280 case HAL_PIXEL_FORMAT_EXYNOS_YV12
:
281 case HAL_PIXEL_FORMAT_YCbCr_420_SP
:
282 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED
:
290 static bool exynos5_format_is_ycrcb(int format
)
292 return format
== HAL_PIXEL_FORMAT_EXYNOS_YV12
;
295 static bool exynos5_format_requires_gscaler(int format
)
297 return (exynos5_format_is_supported_by_gscaler(format
) &&
298 (format
!= HAL_PIXEL_FORMAT_RGBX_8888
) && (format
!= HAL_PIXEL_FORMAT_RGB_565
));
301 static uint8_t exynos5_format_to_bpp(int format
)
304 case HAL_PIXEL_FORMAT_RGBA_8888
:
305 case HAL_PIXEL_FORMAT_RGBX_8888
:
306 case HAL_PIXEL_FORMAT_BGRA_8888
:
309 case HAL_PIXEL_FORMAT_RGBA_5551
:
310 case HAL_PIXEL_FORMAT_RGBA_4444
:
311 case HAL_PIXEL_FORMAT_RGB_565
:
315 ALOGW("unrecognized pixel format %u", format
);
320 static bool is_x_aligned(const hwc_layer_1_t
&layer
, int format
)
322 if (!exynos5_format_is_supported(format
))
325 uint8_t bpp
= exynos5_format_to_bpp(format
);
326 uint8_t pixel_alignment
= 32 / bpp
;
328 return (layer
.displayFrame
.left
% pixel_alignment
) == 0 &&
329 (layer
.displayFrame
.right
% pixel_alignment
) == 0;
332 static bool dst_crop_w_aligned(const hwc_layer_1_t
&layer
, int format
)
335 int dst_crop_w_alignement
;
337 dest_w
= WIDTH(layer
.displayFrame
);
339 /* GSC's dst crop size should be aligned 128Bytes */
340 dst_crop_w_alignement
= 32;
342 return (dest_w
% dst_crop_w_alignement
) == 0;
345 static bool exynos5_supports_gscaler(hwc_layer_1_t
&layer
, int format
,
348 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
350 int max_w
= is_rotated(layer
) ? 2048 : 4800;
351 int max_h
= is_rotated(layer
) ? 2048 : 3344;
353 bool rot90or270
= !!(layer
.transform
& HAL_TRANSFORM_ROT_90
);
354 // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
355 // HAL_TRANSFORM_ROT_180
357 int src_w
= WIDTH(layer
.sourceCrop
), src_h
= HEIGHT(layer
.sourceCrop
);
360 dest_w
= HEIGHT(layer
.displayFrame
);
361 dest_h
= WIDTH(layer
.displayFrame
);
363 dest_w
= WIDTH(layer
.displayFrame
);
364 dest_h
= HEIGHT(layer
.displayFrame
);
366 int max_downscale
= local_path
? 4 : 16;
367 const int max_upscale
= 8;
369 return exynos5_format_is_supported_by_gscaler(format
) &&
370 dst_crop_w_aligned(layer
,format
) &&
371 handle
->stride
<= max_w
&&
372 handle
->stride
% GSC_W_ALIGNMENT
== 0 &&
373 src_w
<= dest_w
* max_downscale
&&
374 dest_w
<= src_w
* max_upscale
&&
375 handle
->vstride
<= max_h
&&
376 handle
->vstride
% GSC_H_ALIGNMENT
== 0 &&
377 src_h
<= dest_h
* max_downscale
&&
378 dest_h
<= src_h
* max_upscale
&&
380 (!rot90or270
|| layer
.sourceCrop
.top
% 2 == 0) &&
381 (!rot90or270
|| layer
.sourceCrop
.left
% 2 == 0);
385 static bool exynos5_requires_gscaler(hwc_layer_1_t
&layer
, int format
)
387 return exynos5_format_requires_gscaler(format
) || is_scaled(layer
)
388 || is_transformed(layer
) || !is_x_aligned(layer
, format
);
391 int hdmi_get_config(struct exynos5_hwc_composer_device_1_t
*dev
)
393 struct v4l2_dv_preset preset
;
394 struct v4l2_dv_enum_preset enum_preset
;
399 if (ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_G_DV_PRESET
, &preset
) < 0) {
400 ALOGE("%s: g_dv_preset error, %d", __func__
, errno
);
405 enum_preset
.index
= index
++;
406 ret
= ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_ENUM_DV_PRESETS
, &enum_preset
);
411 ALOGE("%s: enum_dv_presets error, %d", __func__
, errno
);
415 ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
416 __func__
, enum_preset
.index
, enum_preset
.preset
,
417 enum_preset
.width
, enum_preset
.height
, enum_preset
.name
);
419 if (preset
.preset
== enum_preset
.preset
) {
420 dev
->hdmi_w
= enum_preset
.width
;
421 dev
->hdmi_h
= enum_preset
.height
;
426 return found
? 0 : -1;
429 static enum s3c_fb_blending
exynos5_blending_to_s3c_blending(int32_t blending
)
432 case HWC_BLENDING_NONE
:
433 return S3C_FB_BLENDING_NONE
;
434 case HWC_BLENDING_PREMULT
:
435 return S3C_FB_BLENDING_PREMULT
;
436 case HWC_BLENDING_COVERAGE
:
437 return S3C_FB_BLENDING_COVERAGE
;
440 return S3C_FB_BLENDING_MAX
;
444 static bool exynos5_blending_is_supported(int32_t blending
)
446 return exynos5_blending_to_s3c_blending(blending
) < S3C_FB_BLENDING_MAX
;
450 static int hdmi_enable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
456 struct v4l2_requestbuffers reqbuf
;
457 memset(&reqbuf
, 0, sizeof(reqbuf
));
458 reqbuf
.count
= NUM_HDMI_BUFFERS
;
459 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
460 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
461 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0) {
462 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
466 if (reqbuf
.count
!= NUM_HDMI_BUFFERS
) {
467 ALOGE("%s: layer%d: didn't get buffer", __func__
, hl
.id
);
472 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_PIXEL_BLEND_ENABLE
, 1) < 0) {
473 ALOGE("%s: layer%d: PIXEL_BLEND_ENABLE failed %d", __func__
,
479 ALOGV("%s: layer%d enabled", __func__
, hl
.id
);
484 static void hdmi_disable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
491 if (exynos_v4l2_streamoff(hl
.fd
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) < 0)
492 ALOGE("%s: layer%d: streamoff failed %d", __func__
, hl
.id
, errno
);
493 hl
.streaming
= false;
496 struct v4l2_requestbuffers reqbuf
;
497 memset(&reqbuf
, 0, sizeof(reqbuf
));
498 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
499 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
500 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0)
501 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
503 memset(&hl
.cfg
, 0, sizeof(hl
.cfg
));
508 ALOGV("%s: layer%d disabled", __func__
, hl
.id
);
511 static int hdmi_enable(struct exynos5_hwc_composer_device_1_t
*dev
)
513 if (dev
->hdmi_enabled
)
516 if (dev
->hdmi_blanked
)
519 struct v4l2_subdev_format sd_fmt
;
520 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
521 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
522 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
523 sd_fmt
.format
.width
= dev
->hdmi_w
;
524 sd_fmt
.format
.height
= dev
->hdmi_h
;
525 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
526 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
527 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
531 struct v4l2_subdev_crop sd_crop
;
532 memset(&sd_crop
, 0, sizeof(sd_crop
));
533 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
534 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
535 sd_crop
.rect
.width
= dev
->hdmi_w
;
536 sd_crop
.rect
.height
= dev
->hdmi_h
;
537 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
538 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
542 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
543 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
544 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
545 sd_fmt
.format
.width
= dev
->hdmi_w
;
546 sd_fmt
.format
.height
= dev
->hdmi_h
;
547 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
548 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
549 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
553 memset(&sd_crop
, 0, sizeof(sd_crop
));
554 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
555 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
556 sd_crop
.rect
.width
= dev
->hdmi_w
;
557 sd_crop
.rect
.height
= dev
->hdmi_h
;
558 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
559 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
563 hdmi_enable_layer(dev
, dev
->hdmi_layers
[1]);
565 dev
->hdmi_enabled
= true;
569 static void hdmi_disable(struct exynos5_hwc_composer_device_1_t
*dev
)
571 if (!dev
->hdmi_enabled
)
574 hdmi_disable_layer(dev
, dev
->hdmi_layers
[0]);
575 hdmi_disable_layer(dev
, dev
->hdmi_layers
[1]);
577 exynos5_cleanup_gsc_m2m(dev
, HDMI_GSC_IDX
);
578 dev
->hdmi_enabled
= false;
581 static int hdmi_output(struct exynos5_hwc_composer_device_1_t
*dev
,
583 hwc_layer_1_t
&layer
,
591 memset(&cfg
, 0, sizeof(cfg
));
592 cfg
.x
= layer
.displayFrame
.left
;
593 cfg
.y
= layer
.displayFrame
.top
;
594 cfg
.w
= WIDTH(layer
.displayFrame
);
595 cfg
.h
= HEIGHT(layer
.displayFrame
);
597 if (gsc_src_cfg_changed(hl
.cfg
, cfg
)) {
598 hdmi_disable_layer(dev
, hl
);
600 struct v4l2_format fmt
;
601 memset(&fmt
, 0, sizeof(fmt
));
602 fmt
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
603 fmt
.fmt
.pix_mp
.width
= cfg
.w
;
604 fmt
.fmt
.pix_mp
.height
= cfg
.h
;
605 fmt
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_BGR32
;
606 fmt
.fmt
.pix_mp
.field
= V4L2_FIELD_ANY
;
607 fmt
.fmt
.pix_mp
.num_planes
= 1;
608 ret
= exynos_v4l2_s_fmt(hl
.fd
, &fmt
);
610 ALOGE("%s: layer%d: s_fmt failed %d", __func__
, hl
.id
, errno
);
614 struct v4l2_subdev_crop sd_crop
;
615 memset(&sd_crop
, 0, sizeof(sd_crop
));
617 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
619 sd_crop
.pad
= MIXER_G1_SUBDEV_PAD_SOURCE
;
620 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
621 sd_crop
.rect
.left
= cfg
.x
;
622 sd_crop
.rect
.top
= cfg
.y
;
623 sd_crop
.rect
.width
= cfg
.w
;
624 sd_crop
.rect
.height
= cfg
.h
;
625 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
626 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
630 hdmi_enable_layer(dev
, hl
);
632 ALOGV("HDMI layer%d configuration:", hl
.id
);
637 struct v4l2_buffer buffer
;
638 struct v4l2_plane planes
[1];
640 if (hl
.queued_buf
== NUM_HDMI_BUFFERS
) {
641 memset(&buffer
, 0, sizeof(buffer
));
642 memset(planes
, 0, sizeof(planes
));
643 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
644 buffer
.memory
= V4L2_MEMORY_DMABUF
;
646 buffer
.m
.planes
= planes
;
647 ret
= exynos_v4l2_dqbuf(hl
.fd
, &buffer
);
649 ALOGE("%s: layer%d: dqbuf failed %d", __func__
, hl
.id
, errno
);
655 memset(&buffer
, 0, sizeof(buffer
));
656 memset(planes
, 0, sizeof(planes
));
657 buffer
.index
= hl
.current_buf
;
658 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
659 buffer
.memory
= V4L2_MEMORY_DMABUF
;
660 buffer
.flags
= V4L2_BUF_FLAG_USE_SYNC
;
661 buffer
.reserved
= acquireFenceFd
;
663 buffer
.m
.planes
= planes
;
664 buffer
.m
.planes
[0].m
.fd
= h
->fd
;
665 if (exynos_v4l2_qbuf(hl
.fd
, &buffer
) < 0) {
666 ALOGE("%s: layer%d: qbuf failed %d", __func__
, hl
.id
, errno
);
672 *releaseFenceFd
= buffer
.reserved
;
674 close(buffer
.reserved
);
677 hl
.current_buf
= (hl
.current_buf
+ 1) % NUM_HDMI_BUFFERS
;
680 if (exynos_v4l2_streamon(hl
.fd
, buffer
.type
) < 0) {
681 ALOGE("%s: layer%d: streamon failed %d", __func__
, hl
.id
, errno
);
689 if (acquireFenceFd
>= 0)
690 close(acquireFenceFd
);
695 bool exynos5_is_offscreen(hwc_layer_1_t
&layer
,
696 struct exynos5_hwc_composer_device_1_t
*pdev
)
698 return layer
.sourceCrop
.left
> pdev
->xres
||
699 layer
.sourceCrop
.right
< 0 ||
700 layer
.sourceCrop
.top
> pdev
->yres
||
701 layer
.sourceCrop
.bottom
< 0;
704 size_t exynos5_visible_width(hwc_layer_1_t
&layer
, int format
,
705 struct exynos5_hwc_composer_device_1_t
*pdev
)
708 if (exynos5_requires_gscaler(layer
, format
))
711 bpp
= exynos5_format_to_bpp(format
);
712 int left
= max(layer
.displayFrame
.left
, 0);
713 int right
= min(layer
.displayFrame
.right
, pdev
->xres
);
715 return (right
- left
) * bpp
/ 8;
718 bool exynos5_supports_overlay(hwc_layer_1_t
&layer
, size_t i
,
719 struct exynos5_hwc_composer_device_1_t
*pdev
)
721 if (layer
.flags
& HWC_SKIP_LAYER
) {
722 ALOGV("\tlayer %u: skipping", i
);
726 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
729 ALOGV("\tlayer %u: handle is NULL", i
);
733 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
734 if (!exynos5_supports_gscaler(layer
, handle
->format
, false)) {
735 ALOGV("\tlayer %u: gscaler required but not supported", i
);
739 if (!exynos5_format_is_supported(handle
->format
)) {
740 ALOGV("\tlayer %u: pixel format %u not supported", i
, handle
->format
);
744 if (!exynos5_blending_is_supported(layer
.blending
)) {
745 ALOGV("\tlayer %u: blending %d not supported", i
, layer
.blending
);
748 if (CC_UNLIKELY(exynos5_is_offscreen(layer
, pdev
))) {
749 ALOGW("\tlayer %u: off-screen", i
);
752 if (exynos5_visible_width(layer
, handle
->format
, pdev
) < BURSTLEN_BYTES
) {
753 ALOGV("\tlayer %u: visible area is too narrow", i
);
760 inline bool intersect(const hwc_rect
&r1
, const hwc_rect
&r2
)
762 return !(r1
.left
> r2
.right
||
763 r1
.right
< r2
.left
||
764 r1
.top
> r2
.bottom
||
768 inline hwc_rect
intersection(const hwc_rect
&r1
, const hwc_rect
&r2
)
771 i
.top
= max(r1
.top
, r2
.top
);
772 i
.bottom
= min(r1
.bottom
, r2
.bottom
);
773 i
.left
= max(r1
.left
, r2
.left
);
774 i
.right
= min(r1
.right
, r2
.right
);
778 static int exynos5_prepare_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
779 hwc_display_contents_1_t
* contents
)
781 ALOGV("preparing %u layers for FIMD", contents
->numHwLayers
);
783 memset(pdev
->bufs
.gsc_map
, 0, sizeof(pdev
->bufs
.gsc_map
));
785 bool force_fb
= pdev
->force_gpu
;
786 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
787 pdev
->bufs
.overlay_map
[i
] = -1;
789 bool fb_needed
= false;
790 size_t first_fb
= 0, last_fb
= 0;
792 // find unsupported overlays
793 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
794 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
796 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
797 ALOGV("\tlayer %u: framebuffer target", i
);
801 if (layer
.compositionType
== HWC_BACKGROUND
&& !force_fb
) {
802 ALOGV("\tlayer %u: background supported", i
);
803 dump_layer(&contents
->hwLayers
[i
]);
807 if (exynos5_supports_overlay(contents
->hwLayers
[i
], i
, pdev
) &&
809 ALOGV("\tlayer %u: overlay supported", i
);
810 layer
.compositionType
= HWC_OVERLAY
;
811 dump_layer(&contents
->hwLayers
[i
]);
820 layer
.compositionType
= HWC_FRAMEBUFFER
;
822 dump_layer(&contents
->hwLayers
[i
]);
825 // can't composite overlays sandwiched between framebuffers
827 for (size_t i
= first_fb
; i
< last_fb
; i
++)
828 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
830 // Incrementally try to add our supported layers to hardware windows.
831 // If adding a layer would violate a hardware constraint, force it
832 // into the framebuffer and try again. (Revisiting the entire list is
833 // necessary because adding a layer to the framebuffer can cause other
834 // windows to retroactively violate constraints.)
838 android::Vector
<hwc_rect
> rects
;
839 android::Vector
<hwc_rect
> overlaps
;
840 size_t pixels_left
, windows_left
;
846 fb_rect
.top
= fb_rect
.left
= 0;
847 fb_rect
.right
= pdev
->xres
- 1;
848 fb_rect
.bottom
= pdev
->yres
- 1;
849 pixels_left
= MAX_PIXELS
- pdev
->xres
* pdev
->yres
;
850 windows_left
= NUM_HW_WINDOWS
- 1;
851 rects
.push_back(fb_rect
);
854 pixels_left
= MAX_PIXELS
;
855 windows_left
= NUM_HW_WINDOWS
;
860 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
861 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
862 if ((layer
.flags
& HWC_SKIP_LAYER
) ||
863 layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
)
866 private_handle_t
*handle
= private_handle_t::dynamicCast(
869 // we've already accounted for the framebuffer above
870 if (layer
.compositionType
== HWC_FRAMEBUFFER
)
873 // only layer 0 can be HWC_BACKGROUND, so we can
874 // unconditionally allow it without extra checks
875 if (layer
.compositionType
== HWC_BACKGROUND
) {
880 size_t pixels_needed
= WIDTH(layer
.displayFrame
) *
881 HEIGHT(layer
.displayFrame
);
882 bool can_compose
= windows_left
&& pixels_needed
<= pixels_left
;
883 bool gsc_required
= exynos5_requires_gscaler(layer
, handle
->format
);
885 can_compose
= can_compose
&& !gsc_used
;
887 // hwc_rect_t right and bottom values are normally exclusive;
888 // the intersection logic is simpler if we make them inclusive
889 hwc_rect_t visible_rect
= layer
.displayFrame
;
890 visible_rect
.right
--; visible_rect
.bottom
--;
892 // no more than 2 layers can overlap on a given pixel
893 for (size_t j
= 0; can_compose
&& j
< overlaps
.size(); j
++) {
894 if (intersect(visible_rect
, overlaps
.itemAt(j
)))
899 layer
.compositionType
= HWC_FRAMEBUFFER
;
901 first_fb
= last_fb
= i
;
905 first_fb
= min(i
, first_fb
);
906 last_fb
= max(i
, last_fb
);
912 for (size_t j
= 0; j
< rects
.size(); j
++) {
913 const hwc_rect_t
&other_rect
= rects
.itemAt(j
);
914 if (intersect(visible_rect
, other_rect
))
915 overlaps
.push_back(intersection(visible_rect
, other_rect
));
917 rects
.push_back(visible_rect
);
918 pixels_left
-= pixels_needed
;
925 for (size_t i
= first_fb
; i
< last_fb
; i
++)
926 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
929 unsigned int nextWindow
= 0;
931 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
932 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
934 if (fb_needed
&& i
== first_fb
) {
935 ALOGV("assigning framebuffer to window %u\n",
941 if (layer
.compositionType
!= HWC_FRAMEBUFFER
&&
942 layer
.compositionType
!= HWC_FRAMEBUFFER_TARGET
) {
943 ALOGV("assigning layer %u to window %u", i
, nextWindow
);
944 pdev
->bufs
.overlay_map
[nextWindow
] = i
;
945 if (layer
.compositionType
== HWC_OVERLAY
) {
946 private_handle_t
*handle
=
947 private_handle_t::dynamicCast(layer
.handle
);
948 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
949 ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS
[FIMD_GSC_IDX
]);
950 pdev
->bufs
.gsc_map
[nextWindow
].mode
=
951 exynos5_gsc_map_t::GSC_M2M
;
952 pdev
->bufs
.gsc_map
[nextWindow
].idx
= FIMD_GSC_IDX
;
960 exynos5_cleanup_gsc_m2m(pdev
, FIMD_GSC_IDX
);
963 pdev
->bufs
.fb_window
= first_fb
;
965 pdev
->bufs
.fb_window
= NO_FB_NEEDED
;
970 static int exynos5_prepare_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
971 hwc_display_contents_1_t
* contents
)
973 ALOGV("preparing %u layers for HDMI", contents
->numHwLayers
);
974 hwc_layer_1_t
*video_layer
= NULL
;
976 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
977 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
979 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
980 ALOGV("\tlayer %u: framebuffer target", i
);
984 if (layer
.compositionType
== HWC_BACKGROUND
) {
985 ALOGV("\tlayer %u: background layer", i
);
991 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
992 if (h
->flags
& GRALLOC_USAGE_PROTECTED
) {
994 video_layer
= &layer
;
995 layer
.compositionType
= HWC_OVERLAY
;
996 ALOGV("\tlayer %u: video layer", i
);
1003 layer
.compositionType
= HWC_FRAMEBUFFER
;
1010 static int exynos5_prepare(hwc_composer_device_1_t
*dev
,
1011 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1013 if (!numDisplays
|| !displays
)
1016 exynos5_hwc_composer_device_1_t
*pdev
=
1017 (exynos5_hwc_composer_device_1_t
*)dev
;
1018 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1019 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1021 if (pdev
->hdmi_hpd
) {
1027 if (fimd_contents
) {
1028 int err
= exynos5_prepare_fimd(pdev
, fimd_contents
);
1033 if (hdmi_contents
) {
1034 int err
= exynos5_prepare_hdmi(pdev
, hdmi_contents
);
1042 static int exynos5_config_gsc_m2m(hwc_layer_1_t
&layer
,
1043 alloc_device_t
* alloc_device
, exynos5_gsc_data_t
*gsc_data
,
1044 int gsc_idx
, int dst_format
)
1046 ALOGV("configuring gscaler %u for memory-to-memory", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1048 private_handle_t
*src_handle
= private_handle_t::dynamicCast(layer
.handle
);
1049 buffer_handle_t dst_buf
;
1050 private_handle_t
*dst_handle
;
1053 exynos_gsc_img src_cfg
, dst_cfg
;
1054 memset(&src_cfg
, 0, sizeof(src_cfg
));
1055 memset(&dst_cfg
, 0, sizeof(dst_cfg
));
1057 src_cfg
.x
= layer
.sourceCrop
.left
;
1058 src_cfg
.y
= layer
.sourceCrop
.top
;
1059 src_cfg
.w
= WIDTH(layer
.sourceCrop
);
1060 src_cfg
.fw
= src_handle
->stride
;
1061 src_cfg
.h
= HEIGHT(layer
.sourceCrop
);
1062 src_cfg
.fh
= src_handle
->vstride
;
1063 src_cfg
.yaddr
= src_handle
->fd
;
1064 if (exynos5_format_is_ycrcb(src_handle
->format
)) {
1065 src_cfg
.uaddr
= src_handle
->fd2
;
1066 src_cfg
.vaddr
= src_handle
->fd1
;
1068 src_cfg
.uaddr
= src_handle
->fd1
;
1069 src_cfg
.vaddr
= src_handle
->fd2
;
1071 src_cfg
.format
= src_handle
->format
;
1072 src_cfg
.drmMode
= !!(src_handle
->flags
& GRALLOC_USAGE_PROTECTED
);
1073 src_cfg
.acquireFenceFd
= layer
.acquireFenceFd
;
1074 layer
.acquireFenceFd
= -1;
1078 dst_cfg
.w
= WIDTH(layer
.displayFrame
);
1079 dst_cfg
.h
= HEIGHT(layer
.displayFrame
);
1080 dst_cfg
.rot
= layer
.transform
;
1081 dst_cfg
.drmMode
= src_cfg
.drmMode
;
1082 dst_cfg
.format
= dst_format
;
1083 dst_cfg
.narrowRgb
= !exynos5_format_is_rgb(src_handle
->format
);
1085 ALOGV("source configuration:");
1086 dump_gsc_img(src_cfg
);
1088 bool reconfigure
= gsc_src_cfg_changed(src_cfg
, gsc_data
->src_cfg
) ||
1089 gsc_dst_cfg_changed(dst_cfg
, gsc_data
->dst_cfg
);
1092 int usage
= GRALLOC_USAGE_SW_READ_NEVER
|
1093 GRALLOC_USAGE_SW_WRITE_NEVER
|
1094 GRALLOC_USAGE_HW_COMPOSER
;
1096 if (src_handle
->flags
& GRALLOC_USAGE_PROTECTED
)
1097 usage
|= GRALLOC_USAGE_PROTECTED
;
1099 int w
= ALIGN(WIDTH(layer
.displayFrame
), GSC_DST_W_ALIGNMENT_RGB888
);
1100 int h
= ALIGN(HEIGHT(layer
.displayFrame
), GSC_DST_H_ALIGNMENT_RGB888
);
1102 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1103 if (gsc_data
->dst_buf
[i
]) {
1104 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1105 gsc_data
->dst_buf
[i
] = NULL
;
1108 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1109 close(gsc_data
->dst_buf_fence
[i
]);
1110 gsc_data
->dst_buf_fence
[i
] = -1;
1113 int ret
= alloc_device
->alloc(alloc_device
, w
, h
,
1114 HAL_PIXEL_FORMAT_RGBX_8888
, usage
, &gsc_data
->dst_buf
[i
],
1117 ALOGE("failed to allocate destination buffer: %s",
1123 gsc_data
->current_buf
= 0;
1126 dst_buf
= gsc_data
->dst_buf
[gsc_data
->current_buf
];
1127 dst_handle
= private_handle_t::dynamicCast(dst_buf
);
1129 dst_cfg
.fw
= dst_handle
->stride
;
1130 dst_cfg
.fh
= dst_handle
->vstride
;
1131 dst_cfg
.yaddr
= dst_handle
->fd
;
1132 dst_cfg
.acquireFenceFd
= gsc_data
->dst_buf_fence
[gsc_data
->current_buf
];
1133 gsc_data
->dst_buf_fence
[gsc_data
->current_buf
] = -1;
1135 ALOGV("destination configuration:");
1136 dump_gsc_img(dst_cfg
);
1138 if (gsc_data
->gsc
) {
1139 ALOGV("reusing open gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1141 ALOGV("opening gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1142 gsc_data
->gsc
= exynos_gsc_create_exclusive(
1143 AVAILABLE_GSC_UNITS
[gsc_idx
], GSC_M2M_MODE
, GSC_DUMMY
, true);
1144 if (!gsc_data
->gsc
) {
1145 ALOGE("failed to create gscaler handle");
1152 ret
= exynos_gsc_stop_exclusive(gsc_data
->gsc
);
1154 ALOGE("failed to stop gscaler %u", gsc_idx
);
1155 goto err_gsc_config
;
1158 ret
= exynos_gsc_config_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1160 ALOGE("failed to configure gscaler %u", gsc_idx
);
1161 goto err_gsc_config
;
1165 ret
= exynos_gsc_run_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1167 ALOGE("failed to run gscaler %u", gsc_idx
);
1168 goto err_gsc_config
;
1171 gsc_data
->src_cfg
= src_cfg
;
1172 gsc_data
->dst_cfg
= dst_cfg
;
1174 layer
.releaseFenceFd
= src_cfg
.releaseFenceFd
;
1179 exynos_gsc_destroy(gsc_data
->gsc
);
1180 gsc_data
->gsc
= NULL
;
1182 if (src_cfg
.acquireFenceFd
>= 0)
1183 close(src_cfg
.acquireFenceFd
);
1184 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1185 if (gsc_data
->dst_buf
[i
]) {
1186 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1187 gsc_data
->dst_buf
[i
] = NULL
;
1189 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1190 close(gsc_data
->dst_buf_fence
[i
]);
1191 gsc_data
->dst_buf_fence
[i
] = -1;
1194 memset(&gsc_data
->src_cfg
, 0, sizeof(gsc_data
->src_cfg
));
1195 memset(&gsc_data
->dst_cfg
, 0, sizeof(gsc_data
->dst_cfg
));
1200 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
1203 exynos5_gsc_data_t
&gsc_data
= pdev
->gsc
[gsc_idx
];
1207 ALOGV("closing gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1209 exynos_gsc_stop_exclusive(gsc_data
.gsc
);
1210 exynos_gsc_destroy(gsc_data
.gsc
);
1211 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1212 if (gsc_data
.dst_buf
[i
])
1213 pdev
->alloc_device
->free(pdev
->alloc_device
, gsc_data
.dst_buf
[i
]);
1214 if (gsc_data
.dst_buf_fence
[i
] >= 0)
1215 close(gsc_data
.dst_buf_fence
[i
]);
1218 memset(&gsc_data
, 0, sizeof(gsc_data
));
1219 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++)
1220 gsc_data
.dst_buf_fence
[i
] = -1;
1223 static void exynos5_config_handle(private_handle_t
*handle
,
1224 hwc_rect_t
&sourceCrop
, hwc_rect_t
&displayFrame
,
1225 int32_t blending
, int fence_fd
, s3c_fb_win_config
&cfg
,
1226 exynos5_hwc_composer_device_1_t
*pdev
)
1229 uint32_t w
= WIDTH(displayFrame
);
1230 uint32_t h
= HEIGHT(displayFrame
);
1231 uint8_t bpp
= exynos5_format_to_bpp(handle
->format
);
1232 uint32_t offset
= (sourceCrop
.top
* handle
->stride
+ sourceCrop
.left
) * bpp
/ 8;
1234 if (displayFrame
.left
< 0) {
1235 unsigned int crop
= -displayFrame
.left
;
1236 ALOGV("layer off left side of screen; cropping %u pixels from left edge",
1240 offset
+= crop
* bpp
/ 8;
1242 x
= displayFrame
.left
;
1245 if (displayFrame
.right
> pdev
->xres
) {
1246 unsigned int crop
= displayFrame
.right
- pdev
->xres
;
1247 ALOGV("layer off right side of screen; cropping %u pixels from right edge",
1252 if (displayFrame
.top
< 0) {
1253 unsigned int crop
= -displayFrame
.top
;
1254 ALOGV("layer off top side of screen; cropping %u pixels from top edge",
1258 offset
+= handle
->stride
* crop
* bpp
/ 8;
1260 y
= displayFrame
.top
;
1263 if (displayFrame
.bottom
> pdev
->yres
) {
1264 int crop
= displayFrame
.bottom
- pdev
->yres
;
1265 ALOGV("layer off bottom side of screen; cropping %u pixels from bottom edge",
1270 cfg
.state
= cfg
.S3C_FB_WIN_STATE_BUFFER
;
1271 cfg
.fd
= handle
->fd
;
1276 cfg
.format
= exynos5_format_to_s3c_format(handle
->format
);
1277 cfg
.offset
= offset
;
1278 cfg
.stride
= handle
->stride
* bpp
/ 8;
1279 cfg
.blending
= exynos5_blending_to_s3c_blending(blending
);
1280 cfg
.fence_fd
= fence_fd
;
1283 static void exynos5_config_overlay(hwc_layer_1_t
*layer
, s3c_fb_win_config
&cfg
,
1284 exynos5_hwc_composer_device_1_t
*pdev
)
1286 if (layer
->compositionType
== HWC_BACKGROUND
) {
1287 hwc_color_t color
= layer
->backgroundColor
;
1288 cfg
.state
= cfg
.S3C_FB_WIN_STATE_COLOR
;
1289 cfg
.color
= (color
.r
<< 16) | (color
.g
<< 8) | color
.b
;
1297 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
->handle
);
1298 exynos5_config_handle(handle
, layer
->sourceCrop
, layer
->displayFrame
,
1299 layer
->blending
, layer
->acquireFenceFd
, cfg
, pdev
);
1302 static int exynos5_post_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1303 hwc_display_contents_1_t
* contents
)
1305 exynos5_hwc_post_data_t
*pdata
= &pdev
->bufs
;
1306 struct s3c_fb_win_config_data win_data
;
1307 struct s3c_fb_win_config
*config
= win_data
.config
;
1309 memset(config
, 0, sizeof(win_data
.config
));
1310 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1311 config
[i
].fence_fd
= -1;
1313 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1314 int layer_idx
= pdata
->overlay_map
[i
];
1315 if (layer_idx
!= -1) {
1316 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1317 private_handle_t
*handle
=
1318 private_handle_t::dynamicCast(layer
.handle
);
1320 if (pdata
->gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1321 int gsc_idx
= pdata
->gsc_map
[i
].idx
;
1322 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1324 // RGBX8888 surfaces are already in the right color order from the GPU,
1325 // RGB565 and YUV surfaces need the Gscaler to swap R & B
1326 int dst_format
= HAL_PIXEL_FORMAT_BGRA_8888
;
1327 if (exynos5_format_is_rgb(handle
->format
) &&
1328 handle
->format
!= HAL_PIXEL_FORMAT_RGB_565
)
1329 dst_format
= HAL_PIXEL_FORMAT_RGBX_8888
;
1331 int err
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
,
1332 gsc_idx
, dst_format
);
1334 ALOGE("failed to configure gscaler %u for layer %u",
1336 pdata
->gsc_map
[i
].mode
= exynos5_gsc_map_t::GSC_NONE
;
1340 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1341 private_handle_t
*dst_handle
=
1342 private_handle_t::dynamicCast(dst_buf
);
1343 hwc_rect_t sourceCrop
= { 0, 0,
1344 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
) };
1345 int fence
= gsc
.dst_cfg
.releaseFenceFd
;
1346 exynos5_config_handle(dst_handle
, sourceCrop
,
1347 layer
.displayFrame
, layer
.blending
, fence
, config
[i
],
1350 exynos5_config_overlay(&layer
, config
[i
], pdev
);
1353 if (i
== 0 && config
[i
].blending
!= S3C_FB_BLENDING_NONE
) {
1354 ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
1355 config
[i
].blending
= S3C_FB_BLENDING_NONE
;
1358 ALOGV("window %u configuration:", i
);
1359 dump_config(config
[i
]);
1362 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1363 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1364 if (config
[i
].fence_fd
!= -1)
1365 close(config
[i
].fence_fd
);
1367 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %s", strerror(errno
));
1371 memcpy(pdev
->last_config
, &win_data
.config
, sizeof(win_data
.config
));
1372 memcpy(pdev
->last_gsc_map
, pdata
->gsc_map
, sizeof(pdata
->gsc_map
));
1373 pdev
->last_fb_window
= pdata
->fb_window
;
1374 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1375 int layer_idx
= pdata
->overlay_map
[i
];
1376 if (layer_idx
!= -1) {
1377 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1378 pdev
->last_handles
[i
] = layer
.handle
;
1382 return win_data
.fence
;
1385 static int exynos5_clear_fimd(exynos5_hwc_composer_device_1_t
*pdev
)
1387 struct s3c_fb_win_config_data win_data
;
1388 memset(&win_data
, 0, sizeof(win_data
));
1390 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1391 LOG_ALWAYS_FATAL_IF(ret
< 0,
1392 "ioctl S3CFB_WIN_CONFIG failed to clear screen: %s",
1394 // the causes of an empty config failing are all unrecoverable
1396 return win_data
.fence
;
1399 static int exynos5_set_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1400 hwc_display_contents_1_t
* contents
)
1402 if (!contents
->dpy
|| !contents
->sur
)
1405 hwc_layer_1_t
*fb_layer
= NULL
;
1408 if (pdev
->bufs
.fb_window
!= NO_FB_NEEDED
) {
1409 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1410 if (contents
->hwLayers
[i
].compositionType
==
1411 HWC_FRAMEBUFFER_TARGET
) {
1412 pdev
->bufs
.overlay_map
[pdev
->bufs
.fb_window
] = i
;
1413 fb_layer
= &contents
->hwLayers
[i
];
1418 if (CC_UNLIKELY(!fb_layer
)) {
1419 ALOGE("framebuffer target expected, but not provided");
1422 ALOGV("framebuffer target buffer:");
1423 dump_layer(fb_layer
);
1429 fence
= exynos5_post_fimd(pdev
, contents
);
1435 fence
= exynos5_clear_fimd(pdev
);
1437 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1438 if (pdev
->bufs
.overlay_map
[i
] != -1) {
1439 hwc_layer_1_t
&layer
=
1440 contents
->hwLayers
[pdev
->bufs
.overlay_map
[i
]];
1441 int dup_fd
= dup(fence
);
1443 ALOGW("release fence dup failed: %s", strerror(errno
));
1444 if (pdev
->bufs
.gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1445 int gsc_idx
= pdev
->bufs
.gsc_map
[i
].idx
;
1446 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1447 gsc
.dst_buf_fence
[gsc
.current_buf
] = dup_fd
;
1448 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1450 layer
.releaseFenceFd
= dup_fd
;
1459 static int exynos5_set_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1460 hwc_display_contents_1_t
* contents
)
1462 hwc_layer_1_t
*fb_layer
= NULL
;
1463 hwc_layer_1_t
*video_layer
= NULL
;
1465 if (!pdev
->hdmi_enabled
) {
1466 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1467 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1468 if (layer
.acquireFenceFd
!= -1) {
1469 close(layer
.acquireFenceFd
);
1470 layer
.acquireFenceFd
= -1;
1476 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1477 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1479 if (layer
.flags
& HWC_SKIP_LAYER
) {
1480 ALOGV("HDMI skipping layer %d", i
);
1484 if (layer
.compositionType
== HWC_OVERLAY
) {
1488 ALOGV("HDMI video layer:");
1491 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[HDMI_GSC_IDX
];
1492 int ret
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
, 1,
1493 HAL_PIXEL_FORMAT_RGBX_8888
);
1495 ALOGE("failed to configure gscaler for video layer");
1499 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1500 private_handle_t
*h
= private_handle_t::dynamicCast(dst_buf
);
1502 int acquireFenceFd
= gsc
.dst_cfg
.releaseFenceFd
;
1503 int releaseFenceFd
= -1;
1505 hdmi_output(pdev
, pdev
->hdmi_layers
[0], layer
, h
, acquireFenceFd
,
1507 video_layer
= &layer
;
1509 gsc
.dst_buf_fence
[gsc
.current_buf
] = releaseFenceFd
;
1510 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1513 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1517 ALOGV("HDMI FB layer:");
1520 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1521 hdmi_output(pdev
, pdev
->hdmi_layers
[1], layer
, h
, layer
.acquireFenceFd
,
1522 &layer
.releaseFenceFd
);
1528 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[0]);
1529 exynos5_cleanup_gsc_m2m(pdev
, HDMI_GSC_IDX
);
1532 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[1]);
1534 if (exynos_v4l2_s_ctrl(pdev
->hdmi_layers
[1].fd
, V4L2_CID_TV_UPDATE
, 1) < 0) {
1535 ALOGE("%s: s_ctrl(CID_TV_UPDATE) failed %d", __func__
, errno
);
1542 static int exynos5_set(struct hwc_composer_device_1
*dev
,
1543 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1545 if (!numDisplays
|| !displays
)
1548 exynos5_hwc_composer_device_1_t
*pdev
=
1549 (exynos5_hwc_composer_device_1_t
*)dev
;
1550 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1551 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1552 int fimd_err
= 0, hdmi_err
= 0;
1555 fimd_err
= exynos5_set_fimd(pdev
, fimd_contents
);
1558 hdmi_err
= exynos5_set_hdmi(pdev
, hdmi_contents
);
1566 static void exynos5_registerProcs(struct hwc_composer_device_1
* dev
,
1567 hwc_procs_t
const* procs
)
1569 struct exynos5_hwc_composer_device_1_t
* pdev
=
1570 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1571 pdev
->procs
= procs
;
1574 static int exynos5_query(struct hwc_composer_device_1
* dev
, int what
, int *value
)
1576 struct exynos5_hwc_composer_device_1_t
*pdev
=
1577 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1580 case HWC_BACKGROUND_LAYER_SUPPORTED
:
1581 // we support the background layer
1584 case HWC_VSYNC_PERIOD
:
1585 // vsync period in nanosecond
1586 value
[0] = pdev
->vsync_period
;
1589 // unsupported query
1595 static int exynos5_eventControl(struct hwc_composer_device_1
*dev
, int dpy
,
1596 int event
, int enabled
)
1598 struct exynos5_hwc_composer_device_1_t
*pdev
=
1599 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1602 case HWC_EVENT_VSYNC
:
1603 __u32 val
= !!enabled
;
1604 int err
= ioctl(pdev
->fd
, S3CFB_SET_VSYNC_INT
, &val
);
1606 ALOGE("vsync ioctl failed");
1616 static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t
*pdev
,
1617 const char *buff
, int len
)
1619 const char *s
= buff
;
1623 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1624 pdev
->hdmi_hpd
= atoi(s
+ strlen("SWITCH_STATE=")) == 1;
1627 if (s
- buff
>= len
)
1631 if (pdev
->hdmi_hpd
) {
1632 if (hdmi_get_config(pdev
)) {
1633 ALOGE("Error reading HDMI configuration");
1634 pdev
->hdmi_hpd
= false;
1638 pdev
->hdmi_blanked
= false;
1641 ALOGV("HDMI HPD changed to %s", pdev
->hdmi_hpd
? "enabled" : "disabled");
1643 ALOGI("HDMI Resolution changed to %dx%d", pdev
->hdmi_h
, pdev
->hdmi_w
);
1645 /* hwc_dev->procs is set right after the device is opened, but there is
1646 * still a race condition where a hotplug event might occur after the open
1647 * but before the procs are registered. */
1649 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, pdev
->hdmi_hpd
);
1652 static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t
*pdev
)
1657 int err
= lseek(pdev
->vsync_fd
, 0, SEEK_SET
);
1659 ALOGE("error seeking to vsync timestamp: %s", strerror(errno
));
1664 err
= read(pdev
->vsync_fd
, buf
, sizeof(buf
));
1666 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1669 buf
[sizeof(buf
) - 1] = '\0';
1672 uint64_t timestamp
= strtoull(buf
, NULL
, 0);
1674 pdev
->procs
->vsync(pdev
->procs
, 0, timestamp
);
1677 static void *hwc_vsync_thread(void *data
)
1679 struct exynos5_hwc_composer_device_1_t
*pdev
=
1680 (struct exynos5_hwc_composer_device_1_t
*)data
;
1681 char uevent_desc
[4096];
1682 memset(uevent_desc
, 0, sizeof(uevent_desc
));
1684 setpriority(PRIO_PROCESS
, 0, HAL_PRIORITY_URGENT_DISPLAY
);
1689 int err
= read(pdev
->vsync_fd
, temp
, sizeof(temp
));
1691 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1695 struct pollfd fds
[2];
1696 fds
[0].fd
= pdev
->vsync_fd
;
1697 fds
[0].events
= POLLPRI
;
1698 fds
[1].fd
= uevent_get_fd();
1699 fds
[1].events
= POLLIN
;
1702 int err
= poll(fds
, 2, -1);
1705 if (fds
[0].revents
& POLLPRI
) {
1706 handle_vsync_event(pdev
);
1708 else if (fds
[1].revents
& POLLIN
) {
1709 int len
= uevent_next_event(uevent_desc
,
1710 sizeof(uevent_desc
) - 2);
1712 bool hdmi
= !strcmp(uevent_desc
,
1713 "change@/devices/virtual/switch/hdmi");
1715 handle_hdmi_uevent(pdev
, uevent_desc
, len
);
1718 else if (err
== -1) {
1721 ALOGE("error in vsync thread: %s", strerror(errno
));
1728 static int exynos5_blank(struct hwc_composer_device_1
*dev
, int disp
, int blank
)
1730 struct exynos5_hwc_composer_device_1_t
*pdev
=
1731 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1734 case HWC_DISPLAY_PRIMARY
: {
1735 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
1736 int err
= ioctl(pdev
->fd
, FBIOBLANK
, fb_blank
);
1739 ALOGI("%sblank ioctl failed (display already %sblanked)",
1740 blank
? "" : "un", blank
? "" : "un");
1742 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
1749 case HWC_DISPLAY_EXTERNAL
:
1750 if (pdev
->hdmi_hpd
) {
1751 if (blank
&& !pdev
->hdmi_blanked
)
1753 pdev
->hdmi_blanked
= !!blank
;
1765 static void exynos5_dump(hwc_composer_device_1
* dev
, char *buff
, int buff_len
)
1770 struct exynos5_hwc_composer_device_1_t
*pdev
=
1771 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1773 android::String8 result
;
1775 result
.appendFormat(" hdmi_enabled=%u\n", pdev
->hdmi_enabled
);
1776 if (pdev
->hdmi_enabled
)
1777 result
.appendFormat(" w=%u, h=%u\n", pdev
->hdmi_w
, pdev
->hdmi_h
);
1779 " type | handle | color | blend | format | position | size | gsc \n"
1780 "----------+----------|----------+-------+--------+---------------+---------------------\n");
1781 // 8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
1783 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1784 struct s3c_fb_win_config
&config
= pdev
->last_config
[i
];
1785 if (config
.state
== config
.S3C_FB_WIN_STATE_DISABLED
) {
1786 result
.appendFormat(" %8s | %8s | %8s | %5s | %6s | %13s | %13s",
1787 "DISABLED", "-", "-", "-", "-", "-", "-");
1790 if (config
.state
== config
.S3C_FB_WIN_STATE_COLOR
)
1791 result
.appendFormat(" %8s | %8s | %8x | %5s | %6s", "COLOR",
1792 "-", config
.color
, "-", "-");
1794 result
.appendFormat(" %8s | %8x | %8s | %5x | %6x",
1795 pdev
->last_fb_window
== i
? "FB" : "OVERLAY",
1796 intptr_t(pdev
->last_handles
[i
]),
1797 "-", config
.blending
, config
.format
);
1799 result
.appendFormat(" | [%5d,%5d] | [%5u,%5u]", config
.x
, config
.y
,
1800 config
.w
, config
.h
);
1802 if (pdev
->last_gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_NONE
)
1803 result
.appendFormat(" | %3s", "-");
1805 result
.appendFormat(" | %3d",
1806 AVAILABLE_GSC_UNITS
[pdev
->last_gsc_map
[i
].idx
]);
1807 result
.append("\n");
1810 strlcpy(buff
, result
.string(), buff_len
);
1813 static int exynos5_getDisplayConfigs(struct hwc_composer_device_1
*dev
,
1814 int disp
, uint32_t *configs
, size_t *numConfigs
)
1816 struct exynos5_hwc_composer_device_1_t
*pdev
=
1817 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1819 if (*numConfigs
== 0)
1822 if (disp
== HWC_DISPLAY_PRIMARY
) {
1826 } else if (disp
== HWC_DISPLAY_EXTERNAL
) {
1827 if (!pdev
->hdmi_hpd
) {
1831 int err
= hdmi_get_config(pdev
);
1844 static int32_t exynos5_fimd_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1845 const uint32_t attribute
)
1848 case HWC_DISPLAY_VSYNC_PERIOD
:
1849 return pdev
->vsync_period
;
1851 case HWC_DISPLAY_WIDTH
:
1854 case HWC_DISPLAY_HEIGHT
:
1857 case HWC_DISPLAY_DPI_X
:
1860 case HWC_DISPLAY_DPI_Y
:
1864 ALOGE("unknown display attribute %u", attribute
);
1869 static int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1870 const uint32_t attribute
)
1873 case HWC_DISPLAY_VSYNC_PERIOD
:
1874 return pdev
->vsync_period
;
1876 case HWC_DISPLAY_WIDTH
:
1877 return pdev
->hdmi_w
;
1879 case HWC_DISPLAY_HEIGHT
:
1880 return pdev
->hdmi_h
;
1882 case HWC_DISPLAY_DPI_X
:
1883 case HWC_DISPLAY_DPI_Y
:
1884 return 0; // unknown
1887 ALOGE("unknown display attribute %u", attribute
);
1892 static int exynos5_getDisplayAttributes(struct hwc_composer_device_1
*dev
,
1893 int disp
, uint32_t config
, const uint32_t *attributes
, int32_t *values
)
1895 struct exynos5_hwc_composer_device_1_t
*pdev
=
1896 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1898 for (int i
= 0; attributes
[i
] != HWC_DISPLAY_NO_ATTRIBUTE
; i
++) {
1899 if (disp
== HWC_DISPLAY_PRIMARY
)
1900 values
[i
] = exynos5_fimd_attribute(pdev
, attributes
[i
]);
1901 else if (disp
== HWC_DISPLAY_EXTERNAL
)
1902 values
[i
] = exynos5_hdmi_attribute(pdev
, attributes
[i
]);
1904 ALOGE("unknown display type %u", disp
);
1912 static int exynos5_close(hw_device_t
* device
);
1914 static int exynos5_open(const struct hw_module_t
*module
, const char *name
,
1915 struct hw_device_t
**device
)
1921 if (strcmp(name
, HWC_HARDWARE_COMPOSER
)) {
1925 struct exynos5_hwc_composer_device_1_t
*dev
;
1926 dev
= (struct exynos5_hwc_composer_device_1_t
*)malloc(sizeof(*dev
));
1927 memset(dev
, 0, sizeof(*dev
));
1929 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
,
1930 (const struct hw_module_t
**)&dev
->gralloc_module
)) {
1931 ALOGE("failed to get gralloc hw module");
1933 goto err_get_module
;
1936 if (gralloc_open((const hw_module_t
*)dev
->gralloc_module
,
1937 &dev
->alloc_device
)) {
1938 ALOGE("failed to open gralloc");
1940 goto err_get_module
;
1943 dev
->fd
= open("/dev/graphics/fb0", O_RDWR
);
1945 ALOGE("failed to open framebuffer");
1950 struct fb_var_screeninfo info
;
1951 if (ioctl(dev
->fd
, FBIOGET_VSCREENINFO
, &info
) == -1) {
1952 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno
));
1957 refreshRate
= 1000000000000LLU /
1959 uint64_t( info
.upper_margin
+ info
.lower_margin
+ info
.yres
)
1960 * ( info
.left_margin
+ info
.right_margin
+ info
.xres
)
1964 if (refreshRate
== 0) {
1965 ALOGW("invalid refresh rate, assuming 60 Hz");
1971 dev
->xdpi
= 1000 * (info
.xres
* 25.4f
) / info
.width
;
1972 dev
->ydpi
= 1000 * (info
.yres
* 25.4f
) / info
.height
;
1973 dev
->vsync_period
= 1000000000 / refreshRate
;
1978 "width = %d mm (%f dpi)\n"
1979 "height = %d mm (%f dpi)\n"
1980 "refresh rate = %d Hz\n",
1981 dev
->xres
, dev
->yres
, info
.width
, dev
->xdpi
/ 1000.0,
1982 info
.height
, dev
->ydpi
/ 1000.0, refreshRate
);
1984 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
1985 for (size_t j
= 0; j
< NUM_GSC_DST_BUFS
; j
++)
1986 dev
->gsc
[i
].dst_buf_fence
[j
] = -1;
1988 dev
->hdmi_mixer0
= open("/dev/v4l-subdev7", O_RDWR
);
1989 if (dev
->hdmi_mixer0
< 0) {
1990 ALOGE("failed to open hdmi mixer0 subdev");
1991 ret
= dev
->hdmi_mixer0
;
1995 dev
->hdmi_layers
[0].id
= 0;
1996 dev
->hdmi_layers
[0].fd
= open("/dev/video16", O_RDWR
);
1997 if (dev
->hdmi_layers
[0].fd
< 0) {
1998 ALOGE("failed to open hdmi layer0 device");
1999 ret
= dev
->hdmi_layers
[0].fd
;
2003 dev
->hdmi_layers
[1].id
= 1;
2004 dev
->hdmi_layers
[1].fd
= open("/dev/video17", O_RDWR
);
2005 if (dev
->hdmi_layers
[1].fd
< 0) {
2006 ALOGE("failed to open hdmi layer1 device");
2007 ret
= dev
->hdmi_layers
[1].fd
;
2011 dev
->vsync_fd
= open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY
);
2012 if (dev
->vsync_fd
< 0) {
2013 ALOGE("failed to open vsync attribute");
2014 ret
= dev
->vsync_fd
;
2018 sw_fd
= open("/sys/class/switch/hdmi/state", O_RDONLY
);
2021 if (read(sw_fd
, &val
, 1) == 1 && val
== '1') {
2022 dev
->hdmi_hpd
= true;
2023 if (hdmi_get_config(dev
)) {
2024 ALOGE("Error reading HDMI configuration");
2025 dev
->hdmi_hpd
= false;
2030 dev
->base
.common
.tag
= HARDWARE_DEVICE_TAG
;
2031 dev
->base
.common
.version
= HWC_DEVICE_API_VERSION_1_1
;
2032 dev
->base
.common
.module
= const_cast<hw_module_t
*>(module
);
2033 dev
->base
.common
.close
= exynos5_close
;
2035 dev
->base
.prepare
= exynos5_prepare
;
2036 dev
->base
.set
= exynos5_set
;
2037 dev
->base
.eventControl
= exynos5_eventControl
;
2038 dev
->base
.blank
= exynos5_blank
;
2039 dev
->base
.query
= exynos5_query
;
2040 dev
->base
.registerProcs
= exynos5_registerProcs
;
2041 dev
->base
.dump
= exynos5_dump
;
2042 dev
->base
.getDisplayConfigs
= exynos5_getDisplayConfigs
;
2043 dev
->base
.getDisplayAttributes
= exynos5_getDisplayAttributes
;
2045 *device
= &dev
->base
.common
;
2047 ret
= pthread_create(&dev
->vsync_thread
, NULL
, hwc_vsync_thread
, dev
);
2049 ALOGE("failed to start vsync thread: %s", strerror(ret
));
2054 char value
[PROPERTY_VALUE_MAX
];
2055 property_get("debug.hwc.force_gpu", value
, "0");
2056 dev
->force_gpu
= atoi(value
);
2061 close(dev
->vsync_fd
);
2063 close(dev
->hdmi_mixer0
);
2065 close(dev
->hdmi_layers
[0].fd
);
2067 close(dev
->hdmi_layers
[1].fd
);
2071 gralloc_close(dev
->alloc_device
);
2077 static int exynos5_close(hw_device_t
*device
)
2079 struct exynos5_hwc_composer_device_1_t
*dev
=
2080 (struct exynos5_hwc_composer_device_1_t
*)device
;
2081 pthread_kill(dev
->vsync_thread
, SIGTERM
);
2082 pthread_join(dev
->vsync_thread
, NULL
);
2083 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2084 exynos5_cleanup_gsc_m2m(dev
, i
);
2085 gralloc_close(dev
->alloc_device
);
2086 close(dev
->vsync_fd
);
2087 close(dev
->hdmi_mixer0
);
2088 close(dev
->hdmi_layers
[0].fd
);
2089 close(dev
->hdmi_layers
[1].fd
);
2094 static struct hw_module_methods_t exynos5_hwc_module_methods
= {
2098 hwc_module_t HAL_MODULE_INFO_SYM
= {
2100 tag
: HARDWARE_MODULE_TAG
,
2101 module_api_version
: HWC_MODULE_API_VERSION_0_1
,
2102 hal_api_version
: HARDWARE_HAL_API_VERSION
,
2103 id
: HWC_HARDWARE_MODULE_ID
,
2104 name
: "Samsung exynos5 hwcomposer module",
2106 methods
: &exynos5_hwc_module_methods
,