2 * Copyright (C) 2012 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include <sys/ioctl.h>
27 #include <sys/resource.h>
33 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
35 #include <cutils/compiler.h>
36 #include <cutils/log.h>
37 #include <cutils/properties.h>
38 #include <hardware/gralloc.h>
39 #include <hardware/hardware.h>
40 #include <hardware/hwcomposer.h>
41 #include <hardware_legacy/uevent.h>
42 #include <utils/String8.h>
43 #include <utils/Vector.h>
45 #include <sync/sync.h>
48 #include "gralloc_priv.h"
49 #include "exynos_gscaler.h"
50 #include "exynos_format.h"
51 #include "exynos_v4l2.h"
52 #include "s5p_tvout_v4l2.h"
54 const size_t NUM_HW_WINDOWS
= 5;
55 const size_t NO_FB_NEEDED
= NUM_HW_WINDOWS
+ 1;
56 const size_t MAX_PIXELS
= 2560 * 1600 * 2;
57 const size_t GSC_W_ALIGNMENT
= 16;
58 const size_t GSC_H_ALIGNMENT
= 16;
59 const size_t GSC_DST_CROP_W_ALIGNMENT_RGB888
= 32;
60 const size_t GSC_DST_W_ALIGNMENT_RGB888
= 32;
61 const size_t GSC_DST_H_ALIGNMENT_RGB888
= 1;
62 const size_t FIMD_GSC_IDX
= 0;
63 const size_t HDMI_GSC_IDX
= 1;
64 const int AVAILABLE_GSC_UNITS
[] = { 0, 3 };
65 const size_t NUM_GSC_UNITS
= sizeof(AVAILABLE_GSC_UNITS
) /
66 sizeof(AVAILABLE_GSC_UNITS
[0]);
67 const size_t BURSTLEN_BYTES
= 16 * 8;
68 const size_t NUM_HDMI_BUFFERS
= 3;
70 struct exynos5_hwc_composer_device_1_t
;
72 struct exynos5_gsc_map_t
{
76 // TODO: GSC_LOCAL_PATH
81 struct exynos5_hwc_post_data_t
{
82 int overlay_map
[NUM_HW_WINDOWS
];
83 exynos5_gsc_map_t gsc_map
[NUM_HW_WINDOWS
];
87 const size_t NUM_GSC_DST_BUFS
= 3;
88 struct exynos5_gsc_data_t
{
90 exynos_gsc_img src_cfg
;
91 exynos_gsc_img dst_cfg
;
92 buffer_handle_t dst_buf
[NUM_GSC_DST_BUFS
];
93 int dst_buf_fence
[NUM_GSC_DST_BUFS
];
108 struct exynos5_hwc_composer_device_1_t
{
109 hwc_composer_device_1_t base
;
113 exynos5_hwc_post_data_t bufs
;
115 const private_module_t
*gralloc_module
;
116 alloc_device_t
*alloc_device
;
117 const hwc_procs_t
*procs
;
118 pthread_t vsync_thread
;
125 int32_t vsync_period
;
135 hdmi_layer_t hdmi_layers
[2];
137 exynos5_gsc_data_t gsc
[NUM_GSC_UNITS
];
139 struct s3c_fb_win_config last_config
[NUM_HW_WINDOWS
];
140 size_t last_fb_window
;
141 const void *last_handles
[NUM_HW_WINDOWS
];
142 exynos5_gsc_map_t last_gsc_map
[NUM_HW_WINDOWS
];
145 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
148 static void dump_handle(private_handle_t
*h
)
150 ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
151 h
->format
, h
->width
, h
->height
, h
->stride
, h
->vstride
);
154 static void dump_layer(hwc_layer_1_t
const *l
)
156 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
157 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
158 l
->compositionType
, l
->flags
, l
->handle
, l
->transform
,
163 l
->sourceCrop
.bottom
,
164 l
->displayFrame
.left
,
166 l
->displayFrame
.right
,
167 l
->displayFrame
.bottom
);
169 if(l
->handle
&& !(l
->flags
& HWC_SKIP_LAYER
))
170 dump_handle(private_handle_t::dynamicCast(l
->handle
));
173 static void dump_config(s3c_fb_win_config
&c
)
175 ALOGV("\tstate = %u", c
.state
);
176 if (c
.state
== c
.S3C_FB_WIN_STATE_BUFFER
) {
177 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
178 "x = %d, y = %d, w = %u, h = %u, "
179 "format = %u, blending = %u",
180 c
.fd
, c
.offset
, c
.stride
,
182 c
.format
, c
.blending
);
184 else if (c
.state
== c
.S3C_FB_WIN_STATE_COLOR
) {
185 ALOGV("\t\tcolor = %u", c
.color
);
189 static void dump_gsc_img(exynos_gsc_img
&c
)
191 ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
192 c
.x
, c
.y
, c
.w
, c
.h
, c
.fw
, c
.fh
);
193 ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
194 c
.yaddr
, c
.uaddr
, c
.vaddr
, c
.rot
, c
.cacheable
, c
.drmMode
);
197 inline int WIDTH(const hwc_rect
&rect
) { return rect
.right
- rect
.left
; }
198 inline int HEIGHT(const hwc_rect
&rect
) { return rect
.bottom
- rect
.top
; }
199 template<typename T
> inline T
max(T a
, T b
) { return (a
> b
) ? a
: b
; }
200 template<typename T
> inline T
min(T a
, T b
) { return (a
< b
) ? a
: b
; }
202 static int dup_or_warn(int fence
)
204 int dup_fd
= dup(fence
);
206 ALOGW("fence dup failed: %s", strerror(errno
));
210 static int merge_or_warn(const char *name
, int f1
, int f2
)
212 int merge_fd
= sync_merge(name
, f1
, f2
);
214 ALOGW("fence merge failed: %s", strerror(errno
));
218 template<typename T
> void align_crop_and_center(T
&w
, T
&h
,
219 hwc_rect_t
*crop
, size_t alignment
)
221 double aspect
= 1.0 * h
/ w
;
222 T w_orig
= w
, h_orig
= h
;
224 w
= ALIGN(w
, alignment
);
225 h
= round(aspect
* w
);
227 crop
->left
= (w
- w_orig
) / 2;
228 crop
->top
= (h
- h_orig
) / 2;
229 crop
->right
= crop
->left
+ w_orig
;
230 crop
->bottom
= crop
->top
+ h_orig
;
234 static bool is_transformed(const hwc_layer_1_t
&layer
)
236 return layer
.transform
!= 0;
239 static bool is_rotated(const hwc_layer_1_t
&layer
)
241 return (layer
.transform
& HAL_TRANSFORM_ROT_90
) ||
242 (layer
.transform
& HAL_TRANSFORM_ROT_180
);
245 static bool is_scaled(const hwc_layer_1_t
&layer
)
247 return WIDTH(layer
.displayFrame
) != WIDTH(layer
.sourceCrop
) ||
248 HEIGHT(layer
.displayFrame
) != HEIGHT(layer
.sourceCrop
);
251 static inline bool gsc_dst_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
253 return c1
.x
!= c2
.x
||
257 c1
.format
!= c2
.format
||
259 c1
.cacheable
!= c2
.cacheable
||
260 c1
.drmMode
!= c2
.drmMode
;
263 static inline bool gsc_src_cfg_changed(exynos_gsc_img
&c1
, exynos_gsc_img
&c2
)
265 return gsc_dst_cfg_changed(c1
, c2
) ||
270 static enum s3c_fb_pixel_format
exynos5_format_to_s3c_format(int format
)
273 case HAL_PIXEL_FORMAT_RGBA_8888
:
274 return S3C_FB_PIXEL_FORMAT_RGBA_8888
;
275 case HAL_PIXEL_FORMAT_RGBX_8888
:
276 return S3C_FB_PIXEL_FORMAT_RGBX_8888
;
277 case HAL_PIXEL_FORMAT_RGB_565
:
278 return S3C_FB_PIXEL_FORMAT_RGB_565
;
279 case HAL_PIXEL_FORMAT_BGRA_8888
:
280 return S3C_FB_PIXEL_FORMAT_BGRA_8888
;
282 return S3C_FB_PIXEL_FORMAT_MAX
;
286 static bool exynos5_format_is_supported(int format
)
288 return exynos5_format_to_s3c_format(format
) < S3C_FB_PIXEL_FORMAT_MAX
;
291 static bool exynos5_format_is_rgb(int format
)
294 case HAL_PIXEL_FORMAT_RGBA_8888
:
295 case HAL_PIXEL_FORMAT_RGBX_8888
:
296 case HAL_PIXEL_FORMAT_RGB_888
:
297 case HAL_PIXEL_FORMAT_RGB_565
:
298 case HAL_PIXEL_FORMAT_BGRA_8888
:
306 static bool exynos5_format_is_supported_by_gscaler(int format
)
309 case HAL_PIXEL_FORMAT_RGBX_8888
:
310 case HAL_PIXEL_FORMAT_RGB_565
:
311 case HAL_PIXEL_FORMAT_EXYNOS_YV12
:
312 case HAL_PIXEL_FORMAT_YCbCr_420_SP
:
313 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED
:
321 static bool exynos5_format_is_ycrcb(int format
)
323 return format
== HAL_PIXEL_FORMAT_EXYNOS_YV12
;
326 static bool exynos5_format_requires_gscaler(int format
)
328 return (exynos5_format_is_supported_by_gscaler(format
) &&
329 (format
!= HAL_PIXEL_FORMAT_RGBX_8888
) && (format
!= HAL_PIXEL_FORMAT_RGB_565
));
332 static uint8_t exynos5_format_to_bpp(int format
)
335 case HAL_PIXEL_FORMAT_RGBA_8888
:
336 case HAL_PIXEL_FORMAT_RGBX_8888
:
337 case HAL_PIXEL_FORMAT_BGRA_8888
:
340 case HAL_PIXEL_FORMAT_RGB_565
:
344 ALOGW("unrecognized pixel format %u", format
);
349 static bool is_x_aligned(const hwc_layer_1_t
&layer
, int format
)
351 if (!exynos5_format_is_supported(format
))
354 uint8_t bpp
= exynos5_format_to_bpp(format
);
355 uint8_t pixel_alignment
= 32 / bpp
;
357 return (layer
.displayFrame
.left
% pixel_alignment
) == 0 &&
358 (layer
.displayFrame
.right
% pixel_alignment
) == 0;
361 static bool dst_crop_w_aligned(int dest_w
)
363 int dst_crop_w_alignement
;
365 /* GSC's dst crop size should be aligned 128Bytes */
366 dst_crop_w_alignement
= GSC_DST_CROP_W_ALIGNMENT_RGB888
;
368 return (dest_w
% dst_crop_w_alignement
) == 0;
371 static bool exynos5_supports_gscaler(hwc_layer_1_t
&layer
, int format
,
374 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
376 int max_w
= is_rotated(layer
) ? 2048 : 4800;
377 int max_h
= is_rotated(layer
) ? 2048 : 3344;
379 bool rot90or270
= !!(layer
.transform
& HAL_TRANSFORM_ROT_90
);
380 // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
381 // HAL_TRANSFORM_ROT_180
383 int src_w
= WIDTH(layer
.sourceCrop
), src_h
= HEIGHT(layer
.sourceCrop
);
386 dest_w
= HEIGHT(layer
.displayFrame
);
387 dest_h
= WIDTH(layer
.displayFrame
);
389 dest_w
= WIDTH(layer
.displayFrame
);
390 dest_h
= HEIGHT(layer
.displayFrame
);
393 if (handle
->flags
& GRALLOC_USAGE_PROTECTED
)
394 align_crop_and_center(dest_w
, dest_h
, NULL
,
395 GSC_DST_CROP_W_ALIGNMENT_RGB888
);
397 int max_downscale
= local_path
? 4 : 16;
398 const int max_upscale
= 8;
400 return exynos5_format_is_supported_by_gscaler(format
) &&
401 dst_crop_w_aligned(dest_w
) &&
402 handle
->stride
<= max_w
&&
403 handle
->stride
% GSC_W_ALIGNMENT
== 0 &&
404 src_w
< dest_w
* max_downscale
&&
405 dest_w
<= src_w
* max_upscale
&&
406 handle
->vstride
<= max_h
&&
407 handle
->vstride
% GSC_H_ALIGNMENT
== 0 &&
408 src_h
< dest_h
* max_downscale
&&
409 dest_h
<= src_h
* max_upscale
&&
411 (!rot90or270
|| layer
.sourceCrop
.top
% 2 == 0) &&
412 (!rot90or270
|| layer
.sourceCrop
.left
% 2 == 0);
416 static bool exynos5_requires_gscaler(hwc_layer_1_t
&layer
, int format
)
418 return exynos5_format_requires_gscaler(format
) || is_scaled(layer
)
419 || is_transformed(layer
) || !is_x_aligned(layer
, format
);
422 int hdmi_get_config(struct exynos5_hwc_composer_device_1_t
*dev
)
424 struct v4l2_dv_preset preset
;
425 struct v4l2_dv_enum_preset enum_preset
;
430 if (ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_G_DV_PRESET
, &preset
) < 0) {
431 ALOGE("%s: g_dv_preset error, %d", __func__
, errno
);
436 enum_preset
.index
= index
++;
437 ret
= ioctl(dev
->hdmi_layers
[0].fd
, VIDIOC_ENUM_DV_PRESETS
, &enum_preset
);
442 ALOGE("%s: enum_dv_presets error, %d", __func__
, errno
);
446 ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
447 __func__
, enum_preset
.index
, enum_preset
.preset
,
448 enum_preset
.width
, enum_preset
.height
, enum_preset
.name
);
450 if (preset
.preset
== enum_preset
.preset
) {
451 dev
->hdmi_w
= enum_preset
.width
;
452 dev
->hdmi_h
= enum_preset
.height
;
457 return found
? 0 : -1;
460 static enum s3c_fb_blending
exynos5_blending_to_s3c_blending(int32_t blending
)
463 case HWC_BLENDING_NONE
:
464 return S3C_FB_BLENDING_NONE
;
465 case HWC_BLENDING_PREMULT
:
466 return S3C_FB_BLENDING_PREMULT
;
467 case HWC_BLENDING_COVERAGE
:
468 return S3C_FB_BLENDING_COVERAGE
;
471 return S3C_FB_BLENDING_MAX
;
475 static bool exynos5_blending_is_supported(int32_t blending
)
477 return exynos5_blending_to_s3c_blending(blending
) < S3C_FB_BLENDING_MAX
;
481 static int hdmi_enable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
487 struct v4l2_requestbuffers reqbuf
;
488 memset(&reqbuf
, 0, sizeof(reqbuf
));
489 reqbuf
.count
= NUM_HDMI_BUFFERS
;
490 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
491 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
492 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0) {
493 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
497 if (reqbuf
.count
!= NUM_HDMI_BUFFERS
) {
498 ALOGE("%s: layer%d: didn't get buffer", __func__
, hl
.id
);
503 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_PIXEL_BLEND_ENABLE
, 1) < 0) {
504 ALOGE("%s: layer%d: PIXEL_BLEND_ENABLE failed %d", __func__
,
510 ALOGV("%s: layer%d enabled", __func__
, hl
.id
);
515 static void hdmi_disable_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
522 if (exynos_v4l2_streamoff(hl
.fd
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) < 0)
523 ALOGE("%s: layer%d: streamoff failed %d", __func__
, hl
.id
, errno
);
524 hl
.streaming
= false;
527 struct v4l2_requestbuffers reqbuf
;
528 memset(&reqbuf
, 0, sizeof(reqbuf
));
529 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
530 reqbuf
.memory
= V4L2_MEMORY_DMABUF
;
531 if (exynos_v4l2_reqbufs(hl
.fd
, &reqbuf
) < 0)
532 ALOGE("%s: layer%d: reqbufs failed %d", __func__
, hl
.id
, errno
);
534 memset(&hl
.cfg
, 0, sizeof(hl
.cfg
));
539 ALOGV("%s: layer%d disabled", __func__
, hl
.id
);
542 static void hdmi_hide_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
545 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_LAYER_PRIO
, 0) < 0)
546 ALOGE("%s: layer%d: LAYER_PRIO failed %d", __func__
,
550 static void hdmi_show_layer(struct exynos5_hwc_composer_device_1_t
*dev
,
553 int prio
= hl
.id
? 3 : 2;
555 if (exynos_v4l2_s_ctrl(hl
.fd
, V4L2_CID_TV_LAYER_PRIO
, prio
) < 0)
556 ALOGE("%s: layer%d: LAYER_PRIO failed %d", __func__
,
560 static int hdmi_enable(struct exynos5_hwc_composer_device_1_t
*dev
)
562 /* hdmi not supported */
563 if (dev
->hdmi_mixer0
< 0)
566 if (dev
->hdmi_enabled
)
569 if (dev
->hdmi_blanked
)
572 struct v4l2_subdev_format sd_fmt
;
573 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
574 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
575 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
576 sd_fmt
.format
.width
= dev
->hdmi_w
;
577 sd_fmt
.format
.height
= dev
->hdmi_h
;
578 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
579 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
580 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
584 struct v4l2_subdev_crop sd_crop
;
585 memset(&sd_crop
, 0, sizeof(sd_crop
));
586 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SINK
;
587 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
588 sd_crop
.rect
.width
= dev
->hdmi_w
;
589 sd_crop
.rect
.height
= dev
->hdmi_h
;
590 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
591 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
595 memset(&sd_fmt
, 0, sizeof(sd_fmt
));
596 sd_fmt
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
597 sd_fmt
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
598 sd_fmt
.format
.width
= dev
->hdmi_w
;
599 sd_fmt
.format
.height
= dev
->hdmi_h
;
600 sd_fmt
.format
.code
= V4L2_MBUS_FMT_XRGB8888_4X8_LE
;
601 if (exynos_subdev_s_fmt(dev
->hdmi_mixer0
, &sd_fmt
) < 0) {
602 ALOGE("%s: s_fmt failed pad=%d", __func__
, sd_fmt
.pad
);
606 memset(&sd_crop
, 0, sizeof(sd_crop
));
607 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
608 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
609 sd_crop
.rect
.width
= dev
->hdmi_w
;
610 sd_crop
.rect
.height
= dev
->hdmi_h
;
611 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
612 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
616 char value
[PROPERTY_VALUE_MAX
];
617 property_get("persist.hdmi.hdcp_enabled", value
, "1");
618 int hdcp_enabled
= atoi(value
);
620 if (exynos_v4l2_s_ctrl(dev
->hdmi_layers
[1].fd
, V4L2_CID_TV_HDCP_ENABLE
,
622 ALOGE("%s: s_ctrl(CID_TV_HDCP_ENABLE) failed %d", __func__
, errno
);
624 /* "3" is RGB709_16_235 */
625 property_get("persist.hdmi.color_range", value
, "3");
626 int color_range
= atoi(value
);
628 if (exynos_v4l2_s_ctrl(dev
->hdmi_layers
[1].fd
, V4L2_CID_TV_SET_COLOR_RANGE
,
630 ALOGE("%s: s_ctrl(CID_TV_COLOR_RANGE) failed %d", __func__
, errno
);
632 hdmi_enable_layer(dev
, dev
->hdmi_layers
[1]);
634 dev
->hdmi_enabled
= true;
638 static void hdmi_disable(struct exynos5_hwc_composer_device_1_t
*dev
)
640 if (!dev
->hdmi_enabled
)
643 hdmi_disable_layer(dev
, dev
->hdmi_layers
[0]);
644 hdmi_disable_layer(dev
, dev
->hdmi_layers
[1]);
646 exynos5_cleanup_gsc_m2m(dev
, HDMI_GSC_IDX
);
647 dev
->hdmi_enabled
= false;
650 static int hdmi_output(struct exynos5_hwc_composer_device_1_t
*dev
,
652 hwc_layer_1_t
&layer
,
660 memset(&cfg
, 0, sizeof(cfg
));
661 cfg
.x
= layer
.displayFrame
.left
;
662 cfg
.y
= layer
.displayFrame
.top
;
663 cfg
.w
= WIDTH(layer
.displayFrame
);
664 cfg
.h
= HEIGHT(layer
.displayFrame
);
666 if (gsc_src_cfg_changed(hl
.cfg
, cfg
)) {
667 hdmi_disable_layer(dev
, hl
);
669 struct v4l2_format fmt
;
670 memset(&fmt
, 0, sizeof(fmt
));
671 fmt
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
672 fmt
.fmt
.pix_mp
.width
= h
->stride
;
673 fmt
.fmt
.pix_mp
.height
= cfg
.h
;
674 fmt
.fmt
.pix_mp
.pixelformat
= V4L2_PIX_FMT_BGR32
;
675 fmt
.fmt
.pix_mp
.field
= V4L2_FIELD_ANY
;
676 fmt
.fmt
.pix_mp
.num_planes
= 1;
677 ret
= exynos_v4l2_s_fmt(hl
.fd
, &fmt
);
679 ALOGE("%s: layer%d: s_fmt failed %d", __func__
, hl
.id
, errno
);
683 struct v4l2_subdev_crop sd_crop
;
684 memset(&sd_crop
, 0, sizeof(sd_crop
));
686 sd_crop
.pad
= MIXER_G0_SUBDEV_PAD_SOURCE
;
688 sd_crop
.pad
= MIXER_G1_SUBDEV_PAD_SOURCE
;
689 sd_crop
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
690 sd_crop
.rect
.left
= cfg
.x
;
691 sd_crop
.rect
.top
= cfg
.y
;
692 sd_crop
.rect
.width
= cfg
.w
;
693 sd_crop
.rect
.height
= cfg
.h
;
694 if (exynos_subdev_s_crop(dev
->hdmi_mixer0
, &sd_crop
) < 0) {
695 ALOGE("%s: s_crop failed pad=%d", __func__
, sd_crop
.pad
);
699 hdmi_enable_layer(dev
, hl
);
701 ALOGV("HDMI layer%d configuration:", hl
.id
);
706 struct v4l2_buffer buffer
;
707 struct v4l2_plane planes
[1];
709 if (hl
.queued_buf
== NUM_HDMI_BUFFERS
) {
710 memset(&buffer
, 0, sizeof(buffer
));
711 memset(planes
, 0, sizeof(planes
));
712 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
713 buffer
.memory
= V4L2_MEMORY_DMABUF
;
715 buffer
.m
.planes
= planes
;
716 ret
= exynos_v4l2_dqbuf(hl
.fd
, &buffer
);
718 ALOGE("%s: layer%d: dqbuf failed %d", __func__
, hl
.id
, errno
);
724 memset(&buffer
, 0, sizeof(buffer
));
725 memset(planes
, 0, sizeof(planes
));
726 buffer
.index
= hl
.current_buf
;
727 buffer
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
728 buffer
.memory
= V4L2_MEMORY_DMABUF
;
729 buffer
.flags
= V4L2_BUF_FLAG_USE_SYNC
;
730 buffer
.reserved
= acquireFenceFd
;
732 buffer
.m
.planes
= planes
;
733 buffer
.m
.planes
[0].m
.fd
= h
->fd
;
734 if (exynos_v4l2_qbuf(hl
.fd
, &buffer
) < 0) {
735 ALOGE("%s: layer%d: qbuf failed %d", __func__
, hl
.id
, errno
);
741 *releaseFenceFd
= buffer
.reserved
;
743 close(buffer
.reserved
);
746 hl
.current_buf
= (hl
.current_buf
+ 1) % NUM_HDMI_BUFFERS
;
749 if (exynos_v4l2_streamon(hl
.fd
, buffer
.type
) < 0) {
750 ALOGE("%s: layer%d: streamon failed %d", __func__
, hl
.id
, errno
);
758 if (acquireFenceFd
>= 0)
759 close(acquireFenceFd
);
764 bool exynos5_is_offscreen(hwc_layer_1_t
&layer
,
765 struct exynos5_hwc_composer_device_1_t
*pdev
)
767 return layer
.displayFrame
.left
> pdev
->xres
||
768 layer
.displayFrame
.right
< 0 ||
769 layer
.displayFrame
.top
> pdev
->yres
||
770 layer
.displayFrame
.bottom
< 0;
773 size_t exynos5_visible_width(hwc_layer_1_t
&layer
, int format
,
774 struct exynos5_hwc_composer_device_1_t
*pdev
)
777 if (exynos5_requires_gscaler(layer
, format
))
780 bpp
= exynos5_format_to_bpp(format
);
781 int left
= max(layer
.displayFrame
.left
, 0);
782 int right
= min(layer
.displayFrame
.right
, pdev
->xres
);
784 return (right
- left
) * bpp
/ 8;
787 bool exynos5_supports_overlay(hwc_layer_1_t
&layer
, size_t i
,
788 struct exynos5_hwc_composer_device_1_t
*pdev
)
790 if (layer
.flags
& HWC_SKIP_LAYER
) {
791 ALOGV("\tlayer %u: skipping", i
);
795 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
.handle
);
798 ALOGV("\tlayer %u: handle is NULL", i
);
802 if (exynos5_visible_width(layer
, handle
->format
, pdev
) < BURSTLEN_BYTES
) {
803 ALOGV("\tlayer %u: visible area is too narrow", i
);
806 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
807 if (!exynos5_supports_gscaler(layer
, handle
->format
, false)) {
808 ALOGV("\tlayer %u: gscaler required but not supported", i
);
812 if (!exynos5_format_is_supported(handle
->format
)) {
813 ALOGV("\tlayer %u: pixel format %u not supported", i
, handle
->format
);
817 if (!exynos5_blending_is_supported(layer
.blending
)) {
818 ALOGV("\tlayer %u: blending %d not supported", i
, layer
.blending
);
821 if (CC_UNLIKELY(exynos5_is_offscreen(layer
, pdev
))) {
822 ALOGW("\tlayer %u: off-screen", i
);
829 inline bool intersect(const hwc_rect
&r1
, const hwc_rect
&r2
)
831 return !(r1
.left
> r2
.right
||
832 r1
.right
< r2
.left
||
833 r1
.top
> r2
.bottom
||
837 inline hwc_rect
intersection(const hwc_rect
&r1
, const hwc_rect
&r2
)
840 i
.top
= max(r1
.top
, r2
.top
);
841 i
.bottom
= min(r1
.bottom
, r2
.bottom
);
842 i
.left
= max(r1
.left
, r2
.left
);
843 i
.right
= min(r1
.right
, r2
.right
);
847 static int exynos5_prepare_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
848 hwc_display_contents_1_t
* contents
)
850 ALOGV("preparing %u layers for FIMD", contents
->numHwLayers
);
852 memset(pdev
->bufs
.gsc_map
, 0, sizeof(pdev
->bufs
.gsc_map
));
854 bool force_fb
= pdev
->force_gpu
;
855 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
856 pdev
->bufs
.overlay_map
[i
] = -1;
858 bool fb_needed
= false;
859 size_t first_fb
= 0, last_fb
= 0;
861 // find unsupported overlays
862 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
863 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
865 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
866 ALOGV("\tlayer %u: framebuffer target", i
);
870 if (layer
.compositionType
== HWC_BACKGROUND
&& !force_fb
) {
871 ALOGV("\tlayer %u: background supported", i
);
872 dump_layer(&contents
->hwLayers
[i
]);
876 if (exynos5_supports_overlay(contents
->hwLayers
[i
], i
, pdev
) &&
878 ALOGV("\tlayer %u: overlay supported", i
);
879 layer
.compositionType
= HWC_OVERLAY
;
880 dump_layer(&contents
->hwLayers
[i
]);
889 layer
.compositionType
= HWC_FRAMEBUFFER
;
891 dump_layer(&contents
->hwLayers
[i
]);
894 // can't composite overlays sandwiched between framebuffers
896 for (size_t i
= first_fb
; i
< last_fb
; i
++)
897 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
899 // Incrementally try to add our supported layers to hardware windows.
900 // If adding a layer would violate a hardware constraint, force it
901 // into the framebuffer and try again. (Revisiting the entire list is
902 // necessary because adding a layer to the framebuffer can cause other
903 // windows to retroactively violate constraints.)
907 android::Vector
<hwc_rect
> rects
;
908 android::Vector
<hwc_rect
> overlaps
;
909 size_t pixels_left
, windows_left
;
915 fb_rect
.top
= fb_rect
.left
= 0;
916 fb_rect
.right
= pdev
->xres
- 1;
917 fb_rect
.bottom
= pdev
->yres
- 1;
918 pixels_left
= MAX_PIXELS
- pdev
->xres
* pdev
->yres
;
919 windows_left
= NUM_HW_WINDOWS
- 1;
920 rects
.push_back(fb_rect
);
923 pixels_left
= MAX_PIXELS
;
924 windows_left
= NUM_HW_WINDOWS
;
929 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
930 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
931 if ((layer
.flags
& HWC_SKIP_LAYER
) ||
932 layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
)
935 private_handle_t
*handle
= private_handle_t::dynamicCast(
938 // we've already accounted for the framebuffer above
939 if (layer
.compositionType
== HWC_FRAMEBUFFER
)
942 // only layer 0 can be HWC_BACKGROUND, so we can
943 // unconditionally allow it without extra checks
944 if (layer
.compositionType
== HWC_BACKGROUND
) {
949 size_t pixels_needed
= WIDTH(layer
.displayFrame
) *
950 HEIGHT(layer
.displayFrame
);
951 bool can_compose
= windows_left
&& pixels_needed
<= pixels_left
;
952 bool gsc_required
= exynos5_requires_gscaler(layer
, handle
->format
);
954 can_compose
= can_compose
&& !gsc_used
;
956 // hwc_rect_t right and bottom values are normally exclusive;
957 // the intersection logic is simpler if we make them inclusive
958 hwc_rect_t visible_rect
= layer
.displayFrame
;
959 visible_rect
.right
--; visible_rect
.bottom
--;
961 // no more than 2 layers can overlap on a given pixel
962 for (size_t j
= 0; can_compose
&& j
< overlaps
.size(); j
++) {
963 if (intersect(visible_rect
, overlaps
.itemAt(j
)))
968 layer
.compositionType
= HWC_FRAMEBUFFER
;
970 first_fb
= last_fb
= i
;
974 first_fb
= min(i
, first_fb
);
975 last_fb
= max(i
, last_fb
);
981 for (size_t j
= 0; j
< rects
.size(); j
++) {
982 const hwc_rect_t
&other_rect
= rects
.itemAt(j
);
983 if (intersect(visible_rect
, other_rect
))
984 overlaps
.push_back(intersection(visible_rect
, other_rect
));
986 rects
.push_back(visible_rect
);
987 pixels_left
-= pixels_needed
;
994 for (size_t i
= first_fb
; i
< last_fb
; i
++)
995 contents
->hwLayers
[i
].compositionType
= HWC_FRAMEBUFFER
;
998 unsigned int nextWindow
= 0;
1000 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1001 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1003 if (fb_needed
&& i
== first_fb
) {
1004 ALOGV("assigning framebuffer to window %u\n",
1010 if (layer
.compositionType
!= HWC_FRAMEBUFFER
&&
1011 layer
.compositionType
!= HWC_FRAMEBUFFER_TARGET
) {
1012 ALOGV("assigning layer %u to window %u", i
, nextWindow
);
1013 pdev
->bufs
.overlay_map
[nextWindow
] = i
;
1014 if (layer
.compositionType
== HWC_OVERLAY
) {
1015 private_handle_t
*handle
=
1016 private_handle_t::dynamicCast(layer
.handle
);
1017 if (exynos5_requires_gscaler(layer
, handle
->format
)) {
1018 ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS
[FIMD_GSC_IDX
]);
1019 pdev
->bufs
.gsc_map
[nextWindow
].mode
=
1020 exynos5_gsc_map_t::GSC_M2M
;
1021 pdev
->bufs
.gsc_map
[nextWindow
].idx
= FIMD_GSC_IDX
;
1029 exynos5_cleanup_gsc_m2m(pdev
, FIMD_GSC_IDX
);
1032 pdev
->bufs
.fb_window
= first_fb
;
1034 pdev
->bufs
.fb_window
= NO_FB_NEEDED
;
1039 static int exynos5_prepare_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1040 hwc_display_contents_1_t
* contents
)
1042 ALOGV("preparing %u layers for HDMI", contents
->numHwLayers
);
1043 hwc_layer_1_t
*video_layer
= NULL
;
1045 pdev
->hdmi_fb_needed
= false;
1047 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1048 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1050 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1051 ALOGV("\tlayer %u: framebuffer target", i
);
1055 if (layer
.compositionType
== HWC_BACKGROUND
) {
1056 ALOGV("\tlayer %u: background layer", i
);
1062 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1063 if (h
->flags
& GRALLOC_USAGE_PROTECTED
) {
1065 video_layer
= &layer
;
1066 layer
.compositionType
= HWC_OVERLAY
;
1067 ALOGV("\tlayer %u: video layer", i
);
1074 pdev
->hdmi_fb_needed
= true;
1075 layer
.compositionType
= HWC_FRAMEBUFFER
;
1082 static int exynos5_prepare(hwc_composer_device_1_t
*dev
,
1083 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1085 if (!numDisplays
|| !displays
)
1088 exynos5_hwc_composer_device_1_t
*pdev
=
1089 (exynos5_hwc_composer_device_1_t
*)dev
;
1090 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1091 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1093 if (pdev
->hdmi_hpd
) {
1099 if (fimd_contents
) {
1100 int err
= exynos5_prepare_fimd(pdev
, fimd_contents
);
1105 if (hdmi_contents
) {
1106 int err
= exynos5_prepare_hdmi(pdev
, hdmi_contents
);
1114 static int exynos5_config_gsc_m2m(hwc_layer_1_t
&layer
,
1115 alloc_device_t
* alloc_device
, exynos5_gsc_data_t
*gsc_data
,
1116 int gsc_idx
, int dst_format
, hwc_rect_t
*sourceCrop
)
1118 ALOGV("configuring gscaler %u for memory-to-memory", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1120 private_handle_t
*src_handle
= private_handle_t::dynamicCast(layer
.handle
);
1121 buffer_handle_t dst_buf
;
1122 private_handle_t
*dst_handle
;
1125 exynos_gsc_img src_cfg
, dst_cfg
;
1126 memset(&src_cfg
, 0, sizeof(src_cfg
));
1127 memset(&dst_cfg
, 0, sizeof(dst_cfg
));
1129 hwc_rect_t sourceCropTemp
;
1131 sourceCrop
= &sourceCropTemp
;
1133 src_cfg
.x
= layer
.sourceCrop
.left
;
1134 src_cfg
.y
= layer
.sourceCrop
.top
;
1135 src_cfg
.w
= WIDTH(layer
.sourceCrop
);
1136 src_cfg
.fw
= src_handle
->stride
;
1137 src_cfg
.h
= HEIGHT(layer
.sourceCrop
);
1138 src_cfg
.fh
= src_handle
->vstride
;
1139 src_cfg
.yaddr
= src_handle
->fd
;
1140 if (exynos5_format_is_ycrcb(src_handle
->format
)) {
1141 src_cfg
.uaddr
= src_handle
->fd2
;
1142 src_cfg
.vaddr
= src_handle
->fd1
;
1144 src_cfg
.uaddr
= src_handle
->fd1
;
1145 src_cfg
.vaddr
= src_handle
->fd2
;
1147 src_cfg
.format
= src_handle
->format
;
1148 src_cfg
.drmMode
= !!(src_handle
->flags
& GRALLOC_USAGE_PROTECTED
);
1149 src_cfg
.acquireFenceFd
= layer
.acquireFenceFd
;
1150 layer
.acquireFenceFd
= -1;
1154 dst_cfg
.w
= WIDTH(layer
.displayFrame
);
1155 dst_cfg
.h
= HEIGHT(layer
.displayFrame
);
1156 dst_cfg
.rot
= layer
.transform
;
1157 dst_cfg
.drmMode
= src_cfg
.drmMode
;
1158 dst_cfg
.format
= dst_format
;
1159 dst_cfg
.narrowRgb
= !exynos5_format_is_rgb(src_handle
->format
);
1160 if (dst_cfg
.drmMode
)
1161 align_crop_and_center(dst_cfg
.w
, dst_cfg
.h
, sourceCrop
,
1162 GSC_DST_CROP_W_ALIGNMENT_RGB888
);
1164 ALOGV("source configuration:");
1165 dump_gsc_img(src_cfg
);
1167 bool reconfigure
= gsc_src_cfg_changed(src_cfg
, gsc_data
->src_cfg
) ||
1168 gsc_dst_cfg_changed(dst_cfg
, gsc_data
->dst_cfg
);
1171 int usage
= GRALLOC_USAGE_SW_READ_NEVER
|
1172 GRALLOC_USAGE_SW_WRITE_NEVER
|
1173 GRALLOC_USAGE_HW_COMPOSER
;
1175 if (src_handle
->flags
& GRALLOC_USAGE_PROTECTED
)
1176 usage
|= GRALLOC_USAGE_PROTECTED
;
1178 int w
= ALIGN(dst_cfg
.w
, GSC_DST_W_ALIGNMENT_RGB888
);
1179 int h
= ALIGN(dst_cfg
.h
, GSC_DST_H_ALIGNMENT_RGB888
);
1181 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1182 if (gsc_data
->dst_buf
[i
]) {
1183 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1184 gsc_data
->dst_buf
[i
] = NULL
;
1187 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1188 close(gsc_data
->dst_buf_fence
[i
]);
1189 gsc_data
->dst_buf_fence
[i
] = -1;
1192 int ret
= alloc_device
->alloc(alloc_device
, w
, h
,
1193 HAL_PIXEL_FORMAT_RGBX_8888
, usage
, &gsc_data
->dst_buf
[i
],
1196 ALOGE("failed to allocate destination buffer: %s",
1202 gsc_data
->current_buf
= 0;
1205 dst_buf
= gsc_data
->dst_buf
[gsc_data
->current_buf
];
1206 dst_handle
= private_handle_t::dynamicCast(dst_buf
);
1208 dst_cfg
.fw
= dst_handle
->stride
;
1209 dst_cfg
.fh
= dst_handle
->vstride
;
1210 dst_cfg
.yaddr
= dst_handle
->fd
;
1211 dst_cfg
.acquireFenceFd
= gsc_data
->dst_buf_fence
[gsc_data
->current_buf
];
1212 gsc_data
->dst_buf_fence
[gsc_data
->current_buf
] = -1;
1214 ALOGV("destination configuration:");
1215 dump_gsc_img(dst_cfg
);
1217 if ((int)dst_cfg
.w
!= WIDTH(layer
.displayFrame
))
1218 ALOGV("padding %u x %u output to %u x %u and cropping to {%u,%u,%u,%u}",
1219 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
),
1220 dst_cfg
.w
, dst_cfg
.h
, sourceCrop
->left
, sourceCrop
->top
,
1221 sourceCrop
->right
, sourceCrop
->bottom
);
1223 if (gsc_data
->gsc
) {
1224 ALOGV("reusing open gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1226 ALOGV("opening gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1227 gsc_data
->gsc
= exynos_gsc_create_exclusive(
1228 AVAILABLE_GSC_UNITS
[gsc_idx
], GSC_M2M_MODE
, GSC_DUMMY
, true);
1229 if (!gsc_data
->gsc
) {
1230 ALOGE("failed to create gscaler handle");
1237 ret
= exynos_gsc_stop_exclusive(gsc_data
->gsc
);
1239 ALOGE("failed to stop gscaler %u", gsc_idx
);
1240 goto err_gsc_config
;
1243 ret
= exynos_gsc_config_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1245 ALOGE("failed to configure gscaler %u", gsc_idx
);
1246 goto err_gsc_config
;
1250 ret
= exynos_gsc_run_exclusive(gsc_data
->gsc
, &src_cfg
, &dst_cfg
);
1252 ALOGE("failed to run gscaler %u", gsc_idx
);
1253 goto err_gsc_config
;
1256 gsc_data
->src_cfg
= src_cfg
;
1257 gsc_data
->dst_cfg
= dst_cfg
;
1259 layer
.releaseFenceFd
= src_cfg
.releaseFenceFd
;
1264 exynos_gsc_destroy(gsc_data
->gsc
);
1265 gsc_data
->gsc
= NULL
;
1267 if (src_cfg
.acquireFenceFd
>= 0)
1268 close(src_cfg
.acquireFenceFd
);
1269 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1270 if (gsc_data
->dst_buf
[i
]) {
1271 alloc_device
->free(alloc_device
, gsc_data
->dst_buf
[i
]);
1272 gsc_data
->dst_buf
[i
] = NULL
;
1274 if (gsc_data
->dst_buf_fence
[i
] >= 0) {
1275 close(gsc_data
->dst_buf_fence
[i
]);
1276 gsc_data
->dst_buf_fence
[i
] = -1;
1279 memset(&gsc_data
->src_cfg
, 0, sizeof(gsc_data
->src_cfg
));
1280 memset(&gsc_data
->dst_cfg
, 0, sizeof(gsc_data
->dst_cfg
));
1285 static void exynos5_cleanup_gsc_m2m(exynos5_hwc_composer_device_1_t
*pdev
,
1288 exynos5_gsc_data_t
&gsc_data
= pdev
->gsc
[gsc_idx
];
1292 ALOGV("closing gscaler %u", AVAILABLE_GSC_UNITS
[gsc_idx
]);
1294 exynos_gsc_stop_exclusive(gsc_data
.gsc
);
1295 exynos_gsc_destroy(gsc_data
.gsc
);
1296 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++) {
1297 if (gsc_data
.dst_buf
[i
])
1298 pdev
->alloc_device
->free(pdev
->alloc_device
, gsc_data
.dst_buf
[i
]);
1299 if (gsc_data
.dst_buf_fence
[i
] >= 0)
1300 close(gsc_data
.dst_buf_fence
[i
]);
1303 memset(&gsc_data
, 0, sizeof(gsc_data
));
1304 for (size_t i
= 0; i
< NUM_GSC_DST_BUFS
; i
++)
1305 gsc_data
.dst_buf_fence
[i
] = -1;
1308 static void exynos5_config_handle(private_handle_t
*handle
,
1309 hwc_rect_t
&sourceCrop
, hwc_rect_t
&displayFrame
,
1310 int32_t blending
, int fence_fd
, s3c_fb_win_config
&cfg
,
1311 exynos5_hwc_composer_device_1_t
*pdev
)
1314 uint32_t w
= WIDTH(displayFrame
);
1315 uint32_t h
= HEIGHT(displayFrame
);
1316 uint8_t bpp
= exynos5_format_to_bpp(handle
->format
);
1317 uint32_t offset
= (sourceCrop
.top
* handle
->stride
+ sourceCrop
.left
) * bpp
/ 8;
1319 if (displayFrame
.left
< 0) {
1320 unsigned int crop
= -displayFrame
.left
;
1321 ALOGV("layer off left side of screen; cropping %u pixels from left edge",
1325 offset
+= crop
* bpp
/ 8;
1327 x
= displayFrame
.left
;
1330 if (displayFrame
.right
> pdev
->xres
) {
1331 unsigned int crop
= displayFrame
.right
- pdev
->xres
;
1332 ALOGV("layer off right side of screen; cropping %u pixels from right edge",
1337 if (displayFrame
.top
< 0) {
1338 unsigned int crop
= -displayFrame
.top
;
1339 ALOGV("layer off top side of screen; cropping %u pixels from top edge",
1343 offset
+= handle
->stride
* crop
* bpp
/ 8;
1345 y
= displayFrame
.top
;
1348 if (displayFrame
.bottom
> pdev
->yres
) {
1349 int crop
= displayFrame
.bottom
- pdev
->yres
;
1350 ALOGV("layer off bottom side of screen; cropping %u pixels from bottom edge",
1355 cfg
.state
= cfg
.S3C_FB_WIN_STATE_BUFFER
;
1356 cfg
.fd
= handle
->fd
;
1361 cfg
.format
= exynos5_format_to_s3c_format(handle
->format
);
1362 cfg
.offset
= offset
;
1363 cfg
.stride
= handle
->stride
* bpp
/ 8;
1364 cfg
.blending
= exynos5_blending_to_s3c_blending(blending
);
1365 cfg
.fence_fd
= fence_fd
;
1368 static void exynos5_config_overlay(hwc_layer_1_t
*layer
, s3c_fb_win_config
&cfg
,
1369 exynos5_hwc_composer_device_1_t
*pdev
)
1371 if (layer
->compositionType
== HWC_BACKGROUND
) {
1372 hwc_color_t color
= layer
->backgroundColor
;
1373 cfg
.state
= cfg
.S3C_FB_WIN_STATE_COLOR
;
1374 cfg
.color
= (color
.r
<< 16) | (color
.g
<< 8) | color
.b
;
1382 private_handle_t
*handle
= private_handle_t::dynamicCast(layer
->handle
);
1383 exynos5_config_handle(handle
, layer
->sourceCrop
, layer
->displayFrame
,
1384 layer
->blending
, layer
->acquireFenceFd
, cfg
, pdev
);
1387 static int exynos5_post_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1388 hwc_display_contents_1_t
* contents
)
1390 exynos5_hwc_post_data_t
*pdata
= &pdev
->bufs
;
1391 struct s3c_fb_win_config_data win_data
;
1392 struct s3c_fb_win_config
*config
= win_data
.config
;
1394 memset(config
, 0, sizeof(win_data
.config
));
1395 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1396 config
[i
].fence_fd
= -1;
1398 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1399 int layer_idx
= pdata
->overlay_map
[i
];
1400 if (layer_idx
!= -1) {
1401 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1402 private_handle_t
*handle
=
1403 private_handle_t::dynamicCast(layer
.handle
);
1405 if (pdata
->gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1406 int gsc_idx
= pdata
->gsc_map
[i
].idx
;
1407 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1409 // RGBX8888 surfaces are already in the right color order from the GPU,
1410 // RGB565 and YUV surfaces need the Gscaler to swap R & B
1411 int dst_format
= HAL_PIXEL_FORMAT_BGRA_8888
;
1412 if (exynos5_format_is_rgb(handle
->format
) &&
1413 handle
->format
!= HAL_PIXEL_FORMAT_RGB_565
)
1414 dst_format
= HAL_PIXEL_FORMAT_RGBX_8888
;
1416 hwc_rect_t sourceCrop
= { 0, 0,
1417 WIDTH(layer
.displayFrame
), HEIGHT(layer
.displayFrame
) };
1418 int err
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
,
1419 gsc_idx
, dst_format
, &sourceCrop
);
1421 ALOGE("failed to configure gscaler %u for layer %u",
1423 pdata
->gsc_map
[i
].mode
= exynos5_gsc_map_t::GSC_NONE
;
1427 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1428 private_handle_t
*dst_handle
=
1429 private_handle_t::dynamicCast(dst_buf
);
1430 int fence
= gsc
.dst_cfg
.releaseFenceFd
;
1431 exynos5_config_handle(dst_handle
, sourceCrop
,
1432 layer
.displayFrame
, layer
.blending
, fence
, config
[i
],
1435 exynos5_config_overlay(&layer
, config
[i
], pdev
);
1438 if (i
== 0 && config
[i
].blending
!= S3C_FB_BLENDING_NONE
) {
1439 ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
1440 config
[i
].blending
= S3C_FB_BLENDING_NONE
;
1443 ALOGV("window %u configuration:", i
);
1444 dump_config(config
[i
]);
1447 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1448 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++)
1449 if (config
[i
].fence_fd
!= -1)
1450 close(config
[i
].fence_fd
);
1452 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %s", strerror(errno
));
1456 memcpy(pdev
->last_config
, &win_data
.config
, sizeof(win_data
.config
));
1457 memcpy(pdev
->last_gsc_map
, pdata
->gsc_map
, sizeof(pdata
->gsc_map
));
1458 pdev
->last_fb_window
= pdata
->fb_window
;
1459 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1460 int layer_idx
= pdata
->overlay_map
[i
];
1461 if (layer_idx
!= -1) {
1462 hwc_layer_1_t
&layer
= contents
->hwLayers
[layer_idx
];
1463 pdev
->last_handles
[i
] = layer
.handle
;
1467 return win_data
.fence
;
1470 static int exynos5_clear_fimd(exynos5_hwc_composer_device_1_t
*pdev
)
1472 struct s3c_fb_win_config_data win_data
;
1473 memset(&win_data
, 0, sizeof(win_data
));
1475 int ret
= ioctl(pdev
->fd
, S3CFB_WIN_CONFIG
, &win_data
);
1476 LOG_ALWAYS_FATAL_IF(ret
< 0,
1477 "ioctl S3CFB_WIN_CONFIG failed to clear screen: %s",
1479 // the causes of an empty config failing are all unrecoverable
1481 return win_data
.fence
;
1484 static int exynos5_set_fimd(exynos5_hwc_composer_device_1_t
*pdev
,
1485 hwc_display_contents_1_t
* contents
)
1487 hwc_layer_1_t
*fb_layer
= NULL
;
1490 if (pdev
->bufs
.fb_window
!= NO_FB_NEEDED
) {
1491 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1492 if (contents
->hwLayers
[i
].compositionType
==
1493 HWC_FRAMEBUFFER_TARGET
) {
1494 pdev
->bufs
.overlay_map
[pdev
->bufs
.fb_window
] = i
;
1495 fb_layer
= &contents
->hwLayers
[i
];
1500 if (CC_UNLIKELY(!fb_layer
)) {
1501 ALOGE("framebuffer target expected, but not provided");
1504 ALOGV("framebuffer target buffer:");
1505 dump_layer(fb_layer
);
1511 fence
= exynos5_post_fimd(pdev
, contents
);
1517 fence
= exynos5_clear_fimd(pdev
);
1519 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1520 if (pdev
->bufs
.overlay_map
[i
] != -1) {
1521 hwc_layer_1_t
&layer
=
1522 contents
->hwLayers
[pdev
->bufs
.overlay_map
[i
]];
1523 int dup_fd
= dup_or_warn(fence
);
1524 if (pdev
->bufs
.gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_M2M
) {
1525 int gsc_idx
= pdev
->bufs
.gsc_map
[i
].idx
;
1526 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[gsc_idx
];
1527 gsc
.dst_buf_fence
[gsc
.current_buf
] = dup_fd
;
1528 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1530 layer
.releaseFenceFd
= dup_fd
;
1534 contents
->retireFenceFd
= fence
;
1539 static int exynos5_set_hdmi(exynos5_hwc_composer_device_1_t
*pdev
,
1540 hwc_display_contents_1_t
* contents
)
1542 hwc_layer_1_t
*video_layer
= NULL
;
1544 if (!pdev
->hdmi_enabled
) {
1545 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1546 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1547 if (layer
.acquireFenceFd
!= -1) {
1548 close(layer
.acquireFenceFd
);
1549 layer
.acquireFenceFd
= -1;
1555 for (size_t i
= 0; i
< contents
->numHwLayers
; i
++) {
1556 hwc_layer_1_t
&layer
= contents
->hwLayers
[i
];
1558 if (layer
.flags
& HWC_SKIP_LAYER
) {
1559 ALOGV("HDMI skipping layer %d", i
);
1563 if (layer
.compositionType
== HWC_OVERLAY
) {
1567 ALOGV("HDMI video layer:");
1570 exynos5_gsc_data_t
&gsc
= pdev
->gsc
[HDMI_GSC_IDX
];
1571 int ret
= exynos5_config_gsc_m2m(layer
, pdev
->alloc_device
, &gsc
, 1,
1572 HAL_PIXEL_FORMAT_RGBX_8888
, NULL
);
1574 ALOGE("failed to configure gscaler for video layer");
1578 buffer_handle_t dst_buf
= gsc
.dst_buf
[gsc
.current_buf
];
1579 private_handle_t
*h
= private_handle_t::dynamicCast(dst_buf
);
1581 int acquireFenceFd
= gsc
.dst_cfg
.releaseFenceFd
;
1582 int releaseFenceFd
= -1;
1584 hdmi_output(pdev
, pdev
->hdmi_layers
[0], layer
, h
, acquireFenceFd
,
1586 video_layer
= &layer
;
1588 gsc
.dst_buf_fence
[gsc
.current_buf
] = releaseFenceFd
;
1589 gsc
.current_buf
= (gsc
.current_buf
+ 1) % NUM_GSC_DST_BUFS
;
1590 if (contents
->retireFenceFd
< 0)
1591 contents
->retireFenceFd
= dup_or_warn(releaseFenceFd
);
1593 int merged
= merge_or_warn("hdmi",
1594 contents
->retireFenceFd
, layer
.releaseFenceFd
);
1595 close(contents
->retireFenceFd
);
1596 contents
->retireFenceFd
= merged
;
1600 if (layer
.compositionType
== HWC_FRAMEBUFFER_TARGET
) {
1601 if (pdev
->hdmi_fb_needed
&& layer
.handle
) {
1602 ALOGV("HDMI FB layer:");
1605 private_handle_t
*h
= private_handle_t::dynamicCast(layer
.handle
);
1606 hdmi_show_layer(pdev
, pdev
->hdmi_layers
[1]);
1607 hdmi_output(pdev
, pdev
->hdmi_layers
[1], layer
, h
, layer
.acquireFenceFd
,
1608 &layer
.releaseFenceFd
);
1610 if (contents
->retireFenceFd
< 0)
1611 contents
->retireFenceFd
= dup_or_warn(layer
.releaseFenceFd
);
1613 int merged
= merge_or_warn("hdmi",
1614 contents
->retireFenceFd
, layer
.releaseFenceFd
);
1615 close(contents
->retireFenceFd
);
1616 contents
->retireFenceFd
= merged
;
1619 if (layer
.acquireFenceFd
>= 0) {
1620 close(layer
.acquireFenceFd
);
1621 layer
.acquireFenceFd
= -1;
1623 hdmi_hide_layer(pdev
, pdev
->hdmi_layers
[1]);
1629 hdmi_disable_layer(pdev
, pdev
->hdmi_layers
[0]);
1630 exynos5_cleanup_gsc_m2m(pdev
, HDMI_GSC_IDX
);
1633 if (exynos_v4l2_s_ctrl(pdev
->hdmi_layers
[1].fd
, V4L2_CID_TV_UPDATE
, 1) < 0) {
1634 ALOGE("%s: s_ctrl(CID_TV_UPDATE) failed %d", __func__
, errno
);
1641 static int exynos5_set(struct hwc_composer_device_1
*dev
,
1642 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
1644 if (!numDisplays
|| !displays
)
1647 exynos5_hwc_composer_device_1_t
*pdev
=
1648 (exynos5_hwc_composer_device_1_t
*)dev
;
1649 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
1650 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
1651 int fimd_err
= 0, hdmi_err
= 0;
1654 fimd_err
= exynos5_set_fimd(pdev
, fimd_contents
);
1657 hdmi_err
= exynos5_set_hdmi(pdev
, hdmi_contents
);
1665 static void exynos5_registerProcs(struct hwc_composer_device_1
* dev
,
1666 hwc_procs_t
const* procs
)
1668 struct exynos5_hwc_composer_device_1_t
* pdev
=
1669 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1670 pdev
->procs
= procs
;
1673 static int exynos5_query(struct hwc_composer_device_1
* dev
, int what
, int *value
)
1675 struct exynos5_hwc_composer_device_1_t
*pdev
=
1676 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1679 case HWC_BACKGROUND_LAYER_SUPPORTED
:
1680 // we support the background layer
1683 case HWC_VSYNC_PERIOD
:
1684 // vsync period in nanosecond
1685 value
[0] = pdev
->vsync_period
;
1688 // unsupported query
1694 static int exynos5_eventControl(struct hwc_composer_device_1
*dev
, int dpy
,
1695 int event
, int enabled
)
1697 struct exynos5_hwc_composer_device_1_t
*pdev
=
1698 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1701 case HWC_EVENT_VSYNC
:
1702 __u32 val
= !!enabled
;
1703 int err
= ioctl(pdev
->fd
, S3CFB_SET_VSYNC_INT
, &val
);
1705 ALOGE("vsync ioctl failed");
1715 static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t
*pdev
,
1716 const char *buff
, int len
)
1718 const char *s
= buff
;
1722 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1723 pdev
->hdmi_hpd
= atoi(s
+ strlen("SWITCH_STATE=")) == 1;
1726 if (s
- buff
>= len
)
1730 if (pdev
->hdmi_hpd
) {
1731 if (hdmi_get_config(pdev
)) {
1732 ALOGE("Error reading HDMI configuration");
1733 pdev
->hdmi_hpd
= false;
1737 pdev
->hdmi_blanked
= false;
1740 ALOGV("HDMI HPD changed to %s", pdev
->hdmi_hpd
? "enabled" : "disabled");
1742 ALOGI("HDMI Resolution changed to %dx%d", pdev
->hdmi_h
, pdev
->hdmi_w
);
1744 /* hwc_dev->procs is set right after the device is opened, but there is
1745 * still a race condition where a hotplug event might occur after the open
1746 * but before the procs are registered. */
1748 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, pdev
->hdmi_hpd
);
1751 static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t
*pdev
)
1756 int err
= lseek(pdev
->vsync_fd
, 0, SEEK_SET
);
1758 ALOGE("error seeking to vsync timestamp: %s", strerror(errno
));
1763 err
= read(pdev
->vsync_fd
, buf
, sizeof(buf
));
1765 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1768 buf
[sizeof(buf
) - 1] = '\0';
1771 uint64_t timestamp
= strtoull(buf
, NULL
, 0);
1773 pdev
->procs
->vsync(pdev
->procs
, 0, timestamp
);
1776 static void *hwc_vsync_thread(void *data
)
1778 struct exynos5_hwc_composer_device_1_t
*pdev
=
1779 (struct exynos5_hwc_composer_device_1_t
*)data
;
1780 char uevent_desc
[4096];
1781 memset(uevent_desc
, 0, sizeof(uevent_desc
));
1783 setpriority(PRIO_PROCESS
, 0, HAL_PRIORITY_URGENT_DISPLAY
);
1788 int err
= read(pdev
->vsync_fd
, temp
, sizeof(temp
));
1790 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
1794 struct pollfd fds
[2];
1795 fds
[0].fd
= pdev
->vsync_fd
;
1796 fds
[0].events
= POLLPRI
;
1797 fds
[1].fd
= uevent_get_fd();
1798 fds
[1].events
= POLLIN
;
1801 int err
= poll(fds
, 2, -1);
1804 if (fds
[0].revents
& POLLPRI
) {
1805 handle_vsync_event(pdev
);
1807 else if (fds
[1].revents
& POLLIN
) {
1808 int len
= uevent_next_event(uevent_desc
,
1809 sizeof(uevent_desc
) - 2);
1811 bool hdmi
= !strcmp(uevent_desc
,
1812 "change@/devices/virtual/switch/hdmi");
1814 handle_hdmi_uevent(pdev
, uevent_desc
, len
);
1817 else if (err
== -1) {
1820 ALOGE("error in vsync thread: %s", strerror(errno
));
1827 static int exynos5_blank(struct hwc_composer_device_1
*dev
, int disp
, int blank
)
1829 struct exynos5_hwc_composer_device_1_t
*pdev
=
1830 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1833 case HWC_DISPLAY_PRIMARY
: {
1834 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
1835 int err
= ioctl(pdev
->fd
, FBIOBLANK
, fb_blank
);
1838 ALOGI("%sblank ioctl failed (display already %sblanked)",
1839 blank
? "" : "un", blank
? "" : "un");
1841 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
1848 case HWC_DISPLAY_EXTERNAL
:
1849 if (pdev
->hdmi_hpd
) {
1850 if (blank
&& !pdev
->hdmi_blanked
)
1852 pdev
->hdmi_blanked
= !!blank
;
1864 static void exynos5_dump(hwc_composer_device_1
* dev
, char *buff
, int buff_len
)
1869 struct exynos5_hwc_composer_device_1_t
*pdev
=
1870 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1872 android::String8 result
;
1874 result
.appendFormat(" hdmi_enabled=%u\n", pdev
->hdmi_enabled
);
1875 if (pdev
->hdmi_enabled
)
1876 result
.appendFormat(" w=%u, h=%u\n", pdev
->hdmi_w
, pdev
->hdmi_h
);
1878 " type | handle | color | blend | format | position | size | gsc \n"
1879 "----------+----------|----------+-------+--------+---------------+---------------------\n");
1880 // 8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
1882 for (size_t i
= 0; i
< NUM_HW_WINDOWS
; i
++) {
1883 struct s3c_fb_win_config
&config
= pdev
->last_config
[i
];
1884 if (config
.state
== config
.S3C_FB_WIN_STATE_DISABLED
) {
1885 result
.appendFormat(" %8s | %8s | %8s | %5s | %6s | %13s | %13s",
1886 "DISABLED", "-", "-", "-", "-", "-", "-");
1889 if (config
.state
== config
.S3C_FB_WIN_STATE_COLOR
)
1890 result
.appendFormat(" %8s | %8s | %8x | %5s | %6s", "COLOR",
1891 "-", config
.color
, "-", "-");
1893 result
.appendFormat(" %8s | %8x | %8s | %5x | %6x",
1894 pdev
->last_fb_window
== i
? "FB" : "OVERLAY",
1895 intptr_t(pdev
->last_handles
[i
]),
1896 "-", config
.blending
, config
.format
);
1898 result
.appendFormat(" | [%5d,%5d] | [%5u,%5u]", config
.x
, config
.y
,
1899 config
.w
, config
.h
);
1901 if (pdev
->last_gsc_map
[i
].mode
== exynos5_gsc_map_t::GSC_NONE
)
1902 result
.appendFormat(" | %3s", "-");
1904 result
.appendFormat(" | %3d",
1905 AVAILABLE_GSC_UNITS
[pdev
->last_gsc_map
[i
].idx
]);
1906 result
.append("\n");
1909 strlcpy(buff
, result
.string(), buff_len
);
1912 static int exynos5_getDisplayConfigs(struct hwc_composer_device_1
*dev
,
1913 int disp
, uint32_t *configs
, size_t *numConfigs
)
1915 struct exynos5_hwc_composer_device_1_t
*pdev
=
1916 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1918 if (*numConfigs
== 0)
1921 if (disp
== HWC_DISPLAY_PRIMARY
) {
1925 } else if (disp
== HWC_DISPLAY_EXTERNAL
) {
1926 if (!pdev
->hdmi_hpd
) {
1930 int err
= hdmi_get_config(pdev
);
1943 static int32_t exynos5_fimd_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1944 const uint32_t attribute
)
1947 case HWC_DISPLAY_VSYNC_PERIOD
:
1948 return pdev
->vsync_period
;
1950 case HWC_DISPLAY_WIDTH
:
1953 case HWC_DISPLAY_HEIGHT
:
1956 case HWC_DISPLAY_DPI_X
:
1959 case HWC_DISPLAY_DPI_Y
:
1963 ALOGE("unknown display attribute %u", attribute
);
1968 static int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
1969 const uint32_t attribute
)
1972 case HWC_DISPLAY_VSYNC_PERIOD
:
1973 return pdev
->vsync_period
;
1975 case HWC_DISPLAY_WIDTH
:
1976 return pdev
->hdmi_w
;
1978 case HWC_DISPLAY_HEIGHT
:
1979 return pdev
->hdmi_h
;
1981 case HWC_DISPLAY_DPI_X
:
1982 case HWC_DISPLAY_DPI_Y
:
1983 return 0; // unknown
1986 ALOGE("unknown display attribute %u", attribute
);
1991 static int exynos5_getDisplayAttributes(struct hwc_composer_device_1
*dev
,
1992 int disp
, uint32_t config
, const uint32_t *attributes
, int32_t *values
)
1994 struct exynos5_hwc_composer_device_1_t
*pdev
=
1995 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1997 for (int i
= 0; attributes
[i
] != HWC_DISPLAY_NO_ATTRIBUTE
; i
++) {
1998 if (disp
== HWC_DISPLAY_PRIMARY
)
1999 values
[i
] = exynos5_fimd_attribute(pdev
, attributes
[i
]);
2000 else if (disp
== HWC_DISPLAY_EXTERNAL
)
2001 values
[i
] = exynos5_hdmi_attribute(pdev
, attributes
[i
]);
2003 ALOGE("unknown display type %u", disp
);
2011 static int exynos5_close(hw_device_t
* device
);
2013 static void get_screen_res(const char *fbname
, int32_t *xres
, int32_t *yres
,
2020 unsigned int _x
, _y
, _r
;
2022 asprintf(&path
, "/sys/class/graphics/%s/modes", fbname
);
2025 fd
= open(path
, O_RDONLY
);
2028 ret
= read(fd
, buf
, sizeof(buf
));
2031 buf
[sizeof(buf
)-1] = '\0';
2033 ret
= sscanf(buf
, "U:%ux%up-%u", &_x
, &_y
, &_r
);
2037 ALOGI("Using %ux%u %uHz resolution for '%s' from modes list\n",
2038 _x
, _y
, _r
, fbname
);
2040 *xres
= (int32_t)_x
;
2041 *yres
= (int32_t)_y
;
2042 *refresh
= (int32_t)_r
;
2059 static int exynos5_open(const struct hw_module_t
*module
, const char *name
,
2060 struct hw_device_t
**device
)
2066 if (strcmp(name
, HWC_HARDWARE_COMPOSER
)) {
2070 struct exynos5_hwc_composer_device_1_t
*dev
;
2071 dev
= (struct exynos5_hwc_composer_device_1_t
*)malloc(sizeof(*dev
));
2072 memset(dev
, 0, sizeof(*dev
));
2074 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
,
2075 (const struct hw_module_t
**)&dev
->gralloc_module
)) {
2076 ALOGE("failed to get gralloc hw module");
2078 goto err_get_module
;
2081 if (gralloc_open((const hw_module_t
*)dev
->gralloc_module
,
2082 &dev
->alloc_device
)) {
2083 ALOGE("failed to open gralloc");
2085 goto err_get_module
;
2088 dev
->fd
= open("/dev/graphics/fb0", O_RDWR
);
2090 ALOGE("failed to open framebuffer");
2095 struct fb_var_screeninfo info
;
2096 if (ioctl(dev
->fd
, FBIOGET_VSCREENINFO
, &info
) == -1) {
2097 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno
));
2102 get_screen_res("fb0", &dev
->xres
, &dev
->yres
, &refreshRate
);
2103 if (refreshRate
== 0) {
2104 ALOGW("invalid refresh rate, assuming 60 Hz");
2108 dev
->xdpi
= 1000 * (dev
->xres
* 25.4f
) / info
.width
;
2109 dev
->ydpi
= 1000 * (dev
->yres
* 25.4f
) / info
.height
;
2110 dev
->vsync_period
= 1000000000 / refreshRate
;
2115 "width = %d mm (%f dpi)\n"
2116 "height = %d mm (%f dpi)\n"
2117 "refresh rate = %d Hz\n",
2118 dev
->xres
, dev
->yres
, info
.width
, dev
->xdpi
/ 1000.0,
2119 info
.height
, dev
->ydpi
/ 1000.0, refreshRate
);
2121 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2122 for (size_t j
= 0; j
< NUM_GSC_DST_BUFS
; j
++)
2123 dev
->gsc
[i
].dst_buf_fence
[j
] = -1;
2125 dev
->hdmi_mixer0
= open("/dev/v4l-subdev7", O_RDWR
);
2126 if (dev
->hdmi_mixer0
< 0)
2127 ALOGE("failed to open hdmi mixer0 subdev");
2129 dev
->hdmi_layers
[0].id
= 0;
2130 dev
->hdmi_layers
[0].fd
= open("/dev/video16", O_RDWR
);
2131 if (dev
->hdmi_layers
[0].fd
< 0) {
2132 ALOGE("failed to open hdmi layer0 device");
2133 ret
= dev
->hdmi_layers
[0].fd
;
2137 dev
->hdmi_layers
[1].id
= 1;
2138 dev
->hdmi_layers
[1].fd
= open("/dev/video17", O_RDWR
);
2139 if (dev
->hdmi_layers
[1].fd
< 0) {
2140 ALOGE("failed to open hdmi layer1 device");
2141 ret
= dev
->hdmi_layers
[1].fd
;
2145 dev
->vsync_fd
= open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY
);
2146 if (dev
->vsync_fd
< 0) {
2147 ALOGE("failed to open vsync attribute");
2148 ret
= dev
->vsync_fd
;
2152 sw_fd
= open("/sys/class/switch/hdmi/state", O_RDONLY
);
2155 if (read(sw_fd
, &val
, 1) == 1 && val
== '1') {
2156 dev
->hdmi_hpd
= true;
2157 if (hdmi_get_config(dev
)) {
2158 ALOGE("Error reading HDMI configuration");
2159 dev
->hdmi_hpd
= false;
2164 dev
->base
.common
.tag
= HARDWARE_DEVICE_TAG
;
2165 dev
->base
.common
.version
= HWC_DEVICE_API_VERSION_1_1
;
2166 dev
->base
.common
.module
= const_cast<hw_module_t
*>(module
);
2167 dev
->base
.common
.close
= exynos5_close
;
2169 dev
->base
.prepare
= exynos5_prepare
;
2170 dev
->base
.set
= exynos5_set
;
2171 dev
->base
.eventControl
= exynos5_eventControl
;
2172 dev
->base
.blank
= exynos5_blank
;
2173 dev
->base
.query
= exynos5_query
;
2174 dev
->base
.registerProcs
= exynos5_registerProcs
;
2175 dev
->base
.dump
= exynos5_dump
;
2176 dev
->base
.getDisplayConfigs
= exynos5_getDisplayConfigs
;
2177 dev
->base
.getDisplayAttributes
= exynos5_getDisplayAttributes
;
2179 *device
= &dev
->base
.common
;
2181 ret
= pthread_create(&dev
->vsync_thread
, NULL
, hwc_vsync_thread
, dev
);
2183 ALOGE("failed to start vsync thread: %s", strerror(ret
));
2188 char value
[PROPERTY_VALUE_MAX
];
2189 property_get("debug.hwc.force_gpu", value
, "0");
2190 dev
->force_gpu
= atoi(value
);
2195 close(dev
->vsync_fd
);
2197 if (dev
->hdmi_mixer0
>= 0)
2198 close(dev
->hdmi_mixer0
);
2200 close(dev
->hdmi_layers
[0].fd
);
2202 close(dev
->hdmi_layers
[1].fd
);
2206 gralloc_close(dev
->alloc_device
);
2212 static int exynos5_close(hw_device_t
*device
)
2214 struct exynos5_hwc_composer_device_1_t
*dev
=
2215 (struct exynos5_hwc_composer_device_1_t
*)device
;
2216 pthread_kill(dev
->vsync_thread
, SIGTERM
);
2217 pthread_join(dev
->vsync_thread
, NULL
);
2218 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
2219 exynos5_cleanup_gsc_m2m(dev
, i
);
2220 gralloc_close(dev
->alloc_device
);
2221 close(dev
->vsync_fd
);
2222 if (dev
->hdmi_mixer0
>= 0)
2223 close(dev
->hdmi_mixer0
);
2224 close(dev
->hdmi_layers
[0].fd
);
2225 close(dev
->hdmi_layers
[1].fd
);
2230 static struct hw_module_methods_t exynos5_hwc_module_methods
= {
2234 hwc_module_t HAL_MODULE_INFO_SYM
= {
2236 tag
: HARDWARE_MODULE_TAG
,
2237 module_api_version
: HWC_MODULE_API_VERSION_0_1
,
2238 hal_api_version
: HARDWARE_HAL_API_VERSION
,
2239 id
: HWC_HARDWARE_MODULE_ID
,
2240 name
: "Samsung exynos5 hwcomposer module",
2242 methods
: &exynos5_hwc_module_methods
,