hwc.cpp revision 67b2c3161baa125ef239fabb49011f5218989aca
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <errno.h>
17#include <fcntl.h>
18#include <poll.h>
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22
23#include <sys/ioctl.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/resource.h>
27
28#include <s3c-fb.h>
29
30#include <EGL/egl.h>
31
32#define HWC_REMOVE_DEPRECATED_VERSIONS 1
33
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>
43
44#include <sync/sync.h>
45
46#include "ion.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"
52
53const size_t NUM_HW_WINDOWS = 5;
54const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
55const size_t MAX_PIXELS = 2560 * 1600 * 2;
56const size_t GSC_W_ALIGNMENT = 16;
57const size_t GSC_H_ALIGNMENT = 16;
58const int AVAILABLE_GSC_UNITS[] = { 0, 3 };
59const size_t NUM_GSC_UNITS = sizeof(AVAILABLE_GSC_UNITS) /
60        sizeof(AVAILABLE_GSC_UNITS[0]);
61const size_t BURSTLEN_BYTES = 16 * 8;
62
63struct exynos5_hwc_composer_device_1_t;
64
65struct exynos5_gsc_map_t {
66    enum {
67        GSC_NONE = 0,
68        GSC_M2M,
69        // TODO: GSC_LOCAL_PATH
70    } mode;
71    int idx;
72};
73
74struct exynos5_hwc_post_data_t {
75    int                 overlay_map[NUM_HW_WINDOWS];
76    exynos5_gsc_map_t   gsc_map[NUM_HW_WINDOWS];
77    size_t              fb_window;
78};
79
80const size_t NUM_GSC_DST_BUFS = 3;
81struct exynos5_gsc_data_t {
82    void            *gsc;
83    exynos_gsc_img  src_cfg;
84    exynos_gsc_img  dst_cfg;
85    buffer_handle_t dst_buf[NUM_GSC_DST_BUFS];
86    size_t          current_buf;
87};
88
89struct exynos5_hwc_composer_device_1_t {
90    hwc_composer_device_1_t base;
91
92    int                     fd;
93    int                     vsync_fd;
94    exynos5_hwc_post_data_t bufs;
95
96    const private_module_t  *gralloc_module;
97    alloc_device_t          *alloc_device;
98    const hwc_procs_t       *procs;
99    pthread_t               vsync_thread;
100    int                     force_gpu;
101
102    int32_t                 xres;
103    int32_t                 yres;
104    int32_t                 xdpi;
105    int32_t                 ydpi;
106    int32_t                 vsync_period;
107
108    int  hdmi_mixer0;
109    int  hdmi_layer0;
110    int  hdmi_layer1;
111    bool hdmi_hpd;
112    bool hdmi_enabled;
113    bool hdmi_blanked;
114    void *hdmi_gsc;
115    int  hdmi_w;
116    int  hdmi_h;
117    exynos_gsc_img hdmi_src;
118    exynos_gsc_img hdmi_dst;
119
120    exynos5_gsc_data_t      gsc[NUM_GSC_UNITS];
121
122    struct s3c_fb_win_config last_config[NUM_HW_WINDOWS];
123    size_t                  last_fb_window;
124    const void              *last_handles[NUM_HW_WINDOWS];
125    exynos5_gsc_map_t       last_gsc_map[NUM_HW_WINDOWS];
126};
127
128static void dump_handle(private_handle_t *h)
129{
130    ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
131            h->format, h->width, h->height, h->stride, h->vstride);
132}
133
134static void dump_layer(hwc_layer_1_t const *l)
135{
136    ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
137            "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
138            l->compositionType, l->flags, l->handle, l->transform,
139            l->blending,
140            l->sourceCrop.left,
141            l->sourceCrop.top,
142            l->sourceCrop.right,
143            l->sourceCrop.bottom,
144            l->displayFrame.left,
145            l->displayFrame.top,
146            l->displayFrame.right,
147            l->displayFrame.bottom);
148
149    if(l->handle && !(l->flags & HWC_SKIP_LAYER))
150        dump_handle(private_handle_t::dynamicCast(l->handle));
151}
152
153static void dump_config(s3c_fb_win_config &c)
154{
155    ALOGV("\tstate = %u", c.state);
156    if (c.state == c.S3C_FB_WIN_STATE_BUFFER) {
157        ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
158                "x = %d, y = %d, w = %u, h = %u, "
159                "format = %u, blending = %u",
160                c.fd, c.offset, c.stride,
161                c.x, c.y, c.w, c.h,
162                c.format, c.blending);
163    }
164    else if (c.state == c.S3C_FB_WIN_STATE_COLOR) {
165        ALOGV("\t\tcolor = %u", c.color);
166    }
167}
168
169static void dump_gsc_img(exynos_gsc_img &c)
170{
171    ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
172            c.x, c.y, c.w, c.h, c.fw, c.fh);
173    ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
174            c.yaddr, c.uaddr, c.vaddr, c.rot, c.cacheable, c.drmMode);
175}
176
177inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
178inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
179template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
180template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
181
182static bool is_transformed(const hwc_layer_1_t &layer)
183{
184    return layer.transform != 0;
185}
186
187static bool is_rotated(const hwc_layer_1_t &layer)
188{
189    return (layer.transform & HAL_TRANSFORM_ROT_90) ||
190            (layer.transform & HAL_TRANSFORM_ROT_180);
191}
192
193static bool is_scaled(const hwc_layer_1_t &layer)
194{
195    return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) ||
196            HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop);
197}
198
199static inline bool gsc_dst_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2)
200{
201    return c1.x != c2.x ||
202            c1.y != c2.y ||
203            c1.w != c2.w ||
204            c1.h != c2.h ||
205            c1.format != c2.format ||
206            c1.rot != c2.rot ||
207            c1.cacheable != c2.cacheable ||
208            c1.drmMode != c2.drmMode;
209}
210
211static inline bool gsc_src_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2)
212{
213    return gsc_dst_cfg_changed(c1, c2) ||
214            c1.fw != c2.fw ||
215            c1.fh != c2.fh;
216}
217
218static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format)
219{
220    switch (format) {
221    case HAL_PIXEL_FORMAT_RGBA_8888:
222        return S3C_FB_PIXEL_FORMAT_RGBA_8888;
223    case HAL_PIXEL_FORMAT_RGBX_8888:
224        return S3C_FB_PIXEL_FORMAT_RGBX_8888;
225    case HAL_PIXEL_FORMAT_RGBA_5551:
226        return S3C_FB_PIXEL_FORMAT_RGBA_5551;
227    case HAL_PIXEL_FORMAT_RGB_565:
228        return S3C_FB_PIXEL_FORMAT_RGB_565;
229    case HAL_PIXEL_FORMAT_BGRA_8888:
230        return S3C_FB_PIXEL_FORMAT_BGRA_8888;
231    default:
232        return S3C_FB_PIXEL_FORMAT_MAX;
233    }
234}
235
236static bool exynos5_format_is_supported(int format)
237{
238    return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX;
239}
240
241static bool exynos5_format_is_rgb(int format)
242{
243    switch (format) {
244    case HAL_PIXEL_FORMAT_RGBA_8888:
245    case HAL_PIXEL_FORMAT_RGBX_8888:
246    case HAL_PIXEL_FORMAT_RGB_888:
247    case HAL_PIXEL_FORMAT_RGB_565:
248    case HAL_PIXEL_FORMAT_BGRA_8888:
249    case HAL_PIXEL_FORMAT_RGBA_5551:
250    case HAL_PIXEL_FORMAT_RGBA_4444:
251        return true;
252
253    default:
254        return false;
255    }
256}
257
258static bool exynos5_format_is_supported_by_gscaler(int format)
259{
260    switch (format) {
261    case HAL_PIXEL_FORMAT_RGBX_8888:
262    case HAL_PIXEL_FORMAT_RGB_565:
263    case HAL_PIXEL_FORMAT_EXYNOS_YV12:
264    case HAL_PIXEL_FORMAT_YCbCr_420_SP:
265    case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
266        return true;
267
268    default:
269        return false;
270    }
271}
272
273static bool exynos5_format_is_ycrcb(int format)
274{
275    return format == HAL_PIXEL_FORMAT_EXYNOS_YV12;
276}
277
278static bool exynos5_format_requires_gscaler(int format)
279{
280    return (exynos5_format_is_supported_by_gscaler(format) &&
281           (format != HAL_PIXEL_FORMAT_RGBX_8888) && (format != HAL_PIXEL_FORMAT_RGB_565));
282}
283
284static uint8_t exynos5_format_to_bpp(int format)
285{
286    switch (format) {
287    case HAL_PIXEL_FORMAT_RGBA_8888:
288    case HAL_PIXEL_FORMAT_RGBX_8888:
289    case HAL_PIXEL_FORMAT_BGRA_8888:
290        return 32;
291
292    case HAL_PIXEL_FORMAT_RGBA_5551:
293    case HAL_PIXEL_FORMAT_RGBA_4444:
294    case HAL_PIXEL_FORMAT_RGB_565:
295        return 16;
296
297    default:
298        ALOGW("unrecognized pixel format %u", format);
299        return 0;
300    }
301}
302
303static bool is_x_aligned(const hwc_layer_1_t &layer, int format)
304{
305    if (!exynos5_format_is_supported(format))
306        return true;
307
308    uint8_t bpp = exynos5_format_to_bpp(format);
309    uint8_t pixel_alignment = 32 / bpp;
310
311    return (layer.displayFrame.left % pixel_alignment) == 0 &&
312            (layer.displayFrame.right % pixel_alignment) == 0;
313}
314
315static bool exynos5_supports_gscaler(hwc_layer_1_t &layer, int format,
316        bool local_path)
317{
318    private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
319
320    int max_w = is_rotated(layer) ? 2048 : 4800;
321    int max_h = is_rotated(layer) ? 2048 : 3344;
322
323    bool rot90or270 = !!(layer.transform & HAL_TRANSFORM_ROT_90);
324    // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
325    //                               HAL_TRANSFORM_ROT_180
326
327    int src_w = WIDTH(layer.sourceCrop), src_h = HEIGHT(layer.sourceCrop);
328    int dest_w, dest_h;
329    if (rot90or270) {
330        dest_w = HEIGHT(layer.displayFrame);
331        dest_h = WIDTH(layer.displayFrame);
332    } else {
333        dest_w = WIDTH(layer.displayFrame);
334        dest_h = HEIGHT(layer.displayFrame);
335    }
336    int max_downscale = local_path ? 4 : 16;
337    const int max_upscale = 8;
338
339    return exynos5_format_is_supported_by_gscaler(format) &&
340            handle->stride <= max_w &&
341            handle->stride % GSC_W_ALIGNMENT == 0 &&
342            src_w <= dest_w * max_downscale &&
343            dest_w <= src_w * max_upscale &&
344            handle->vstride <= max_h &&
345            handle->vstride % GSC_H_ALIGNMENT == 0 &&
346            src_h <= dest_h * max_downscale &&
347            dest_h <= src_h * max_upscale &&
348            // per 46.2
349            (!rot90or270 || layer.sourceCrop.top % 2 == 0) &&
350            (!rot90or270 || layer.sourceCrop.left % 2 == 0);
351            // per 46.3.1.6
352}
353
354static bool exynos5_requires_gscaler(hwc_layer_1_t &layer, int format)
355{
356    return exynos5_format_requires_gscaler(format) || is_scaled(layer)
357            || is_transformed(layer) || !is_x_aligned(layer, format);
358}
359
360int hdmi_get_config(struct exynos5_hwc_composer_device_1_t *dev)
361{
362    struct v4l2_dv_preset preset;
363    struct v4l2_dv_enum_preset enum_preset;
364    int index = 0;
365    bool found = false;
366    int ret;
367
368    if (ioctl(dev->hdmi_layer0, VIDIOC_G_DV_PRESET, &preset) < 0) {
369        ALOGE("%s: g_dv_preset error, %d", __func__, errno);
370        return -1;
371    }
372
373    while (true) {
374        enum_preset.index = index++;
375        ret = ioctl(dev->hdmi_layer0, VIDIOC_ENUM_DV_PRESETS, &enum_preset);
376
377        if (ret < 0) {
378            if (errno == EINVAL)
379                break;
380            ALOGE("%s: enum_dv_presets error, %d", __func__, errno);
381            return -1;
382        }
383
384        ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
385                __func__, enum_preset.index, enum_preset.preset,
386                enum_preset.width, enum_preset.height, enum_preset.name);
387
388        if (preset.preset == enum_preset.preset) {
389            dev->hdmi_w  = enum_preset.width;
390            dev->hdmi_h  = enum_preset.height;
391            found = true;
392        }
393    }
394
395    return found ? 0 : -1;
396}
397
398static enum s3c_fb_blending exynos5_blending_to_s3c_blending(int32_t blending)
399{
400    switch (blending) {
401    case HWC_BLENDING_NONE:
402        return S3C_FB_BLENDING_NONE;
403    case HWC_BLENDING_PREMULT:
404        return S3C_FB_BLENDING_PREMULT;
405    case HWC_BLENDING_COVERAGE:
406        return S3C_FB_BLENDING_COVERAGE;
407
408    default:
409        return S3C_FB_BLENDING_MAX;
410    }
411}
412
413static bool exynos5_blending_is_supported(int32_t blending)
414{
415    return exynos5_blending_to_s3c_blending(blending) < S3C_FB_BLENDING_MAX;
416}
417
418static int hdmi_start_background(struct exynos5_hwc_composer_device_1_t *dev)
419{
420    struct v4l2_requestbuffers reqbuf;
421    struct v4l2_subdev_format  sd_fmt;
422    struct v4l2_subdev_crop    sd_crop;
423    struct v4l2_format         fmt;
424    struct v4l2_buffer         buffer;
425    struct v4l2_plane          planes[1];
426
427    memset(&reqbuf, 0, sizeof(reqbuf));
428    memset(&sd_fmt, 0, sizeof(sd_fmt));
429    memset(&sd_crop, 0, sizeof(sd_crop));
430    memset(&fmt, 0, sizeof(fmt));
431    memset(&buffer, 0, sizeof(buffer));
432    memset(planes, 0, sizeof(planes));
433
434    sd_fmt.pad   = MIXER_G1_SUBDEV_PAD_SINK;
435    sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
436    sd_fmt.format.width  = 1;
437    sd_fmt.format.height = 1;
438    sd_fmt.format.code   = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
439    if (exynos_subdev_s_fmt(dev->hdmi_mixer0, &sd_fmt) < 0) {
440            ALOGE("%s: s_fmt failed pad=%d", __func__, sd_fmt.pad);
441            return -1;
442    }
443
444    sd_crop.pad   = MIXER_G1_SUBDEV_PAD_SINK;
445    sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
446    sd_crop.rect.left   = 0;
447    sd_crop.rect.top    = 0;
448    sd_crop.rect.width  = 1;
449    sd_crop.rect.height = 1;
450    if (exynos_subdev_s_crop(dev->hdmi_mixer0, &sd_crop) < 0) {
451        ALOGE("%s: set_crop failed pad=%d", __func__, sd_crop.pad);
452        return -1;
453    }
454
455    sd_fmt.pad   = MIXER_G1_SUBDEV_PAD_SOURCE;
456    sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
457    sd_fmt.format.width  = dev->hdmi_w;
458    sd_fmt.format.height = dev->hdmi_h;
459    sd_fmt.format.code   = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
460    if (exynos_subdev_s_fmt(dev->hdmi_mixer0, &sd_fmt) < 0) {
461        ALOGE("%s: s_fmt failed pad=%d", __func__, sd_fmt.pad);
462        return -1;
463    }
464
465    sd_crop.pad   = MIXER_G1_SUBDEV_PAD_SOURCE;
466    sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
467    sd_crop.rect.left   = 0;
468    sd_crop.rect.top    = 0;
469    sd_crop.rect.width  = 1;
470    sd_crop.rect.height = 1;
471    if (exynos_subdev_s_crop(dev->hdmi_mixer0, &sd_crop) < 0) {
472        ALOGE("%s: s_crop failed pad=%d", __func__, sd_crop.pad);
473        return -1;
474    }
475
476    fmt.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
477    fmt.fmt.pix_mp.width       = 1;
478    fmt.fmt.pix_mp.height      = 1;
479    fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_BGR32;
480    fmt.fmt.pix_mp.field       = V4L2_FIELD_ANY;
481    fmt.fmt.pix_mp.num_planes  = 1;
482    if (exynos_v4l2_s_fmt(dev->hdmi_layer1, &fmt) < 0) {
483        ALOGE("%s::videodev set format failed", __func__);
484        return -1;
485    }
486
487    reqbuf.count  = 1;
488    reqbuf.type   = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
489    reqbuf.memory = V4L2_MEMORY_MMAP;
490
491    if (exynos_v4l2_reqbufs(dev->hdmi_layer1, &reqbuf) < 0) {
492        ALOGE("%s: exynos_v4l2_reqbufs failed %d", __func__, errno);
493        return -1;
494    }
495
496    if (reqbuf.count != 1) {
497        ALOGE("%s: didn't get buffer", __func__);
498        return -1;
499    }
500
501    memset(&buffer, 0, sizeof(buffer));
502    buffer.type = reqbuf.type;
503    buffer.memory = V4L2_MEMORY_MMAP;
504    buffer.length = 1;
505    buffer.m.planes = planes;
506    if (exynos_v4l2_querybuf(dev->hdmi_layer1, &buffer) < 0) {
507        ALOGE("%s: exynos_v4l2_querybuf failed %d", __func__, errno);
508        return -1;
509    }
510
511    void *start = mmap(NULL, planes[0].length, PROT_READ | PROT_WRITE,
512                       MAP_SHARED, dev->hdmi_layer1, planes[0].m.mem_offset);
513    if (start == MAP_FAILED) {
514        ALOGE("%s: mmap failed %d", __func__, errno);
515        return -1;
516    }
517
518    memset(start, 0, planes[0].length);
519
520    munmap(start, planes[0].length);
521
522    if (exynos_v4l2_qbuf(dev->hdmi_layer1, &buffer) < 0) {
523        ALOGE("%s: exynos_v4l2_qbuf failed %d", __func__, errno);
524        return -1;
525    }
526
527    if (exynos_v4l2_streamon(dev->hdmi_layer1, buffer.type) < 0) {
528        ALOGE("%s:stream on failed", __func__);
529        return -1;
530    }
531
532    if (exynos_v4l2_s_ctrl(dev->hdmi_layer1, V4L2_CID_TV_LAYER_PRIO, 0) < 0) {
533        ALOGE("%s: s_ctrl LAYER_PRIO failed", __func__);
534        return -1;
535    }
536
537    return 0;
538}
539
540static int hdmi_stop_background(struct exynos5_hwc_composer_device_1_t *dev)
541{
542    struct v4l2_requestbuffers reqbuf;
543
544    if (exynos_v4l2_streamoff(dev->hdmi_layer1, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) < 0) {
545        ALOGE("%s:stream off failed", __func__);
546        return -1;
547    }
548
549    memset(&reqbuf, 0, sizeof(reqbuf));
550    reqbuf.count  = 0;
551    reqbuf.type   = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
552    reqbuf.memory = V4L2_MEMORY_MMAP;
553    if (exynos_v4l2_reqbufs(dev->hdmi_layer1, &reqbuf) < 0) {
554        ALOGE("%s: exynos_v4l2_reqbufs failed %d", __func__, errno);
555        return -1;
556    }
557
558    return 0;
559}
560
561static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev)
562{
563    if (dev->hdmi_enabled)
564        return 0;
565
566    if (dev->hdmi_blanked)
567        return 0;
568
569    dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV);
570    if (!dev->hdmi_gsc) {
571        ALOGE("%s: exynos_gsc_create_exclusive failed", __func__);
572        return -ENODEV;
573    }
574
575    memset(&dev->hdmi_src, 0, sizeof(dev->hdmi_src));
576
577    if (hdmi_start_background(dev) < 0) {
578        ALOGE("%s: hdmi_start_background failed", __func__);
579        return -1;
580    }
581
582    dev->hdmi_enabled = true;
583    return 0;
584}
585
586static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev)
587{
588    if (!dev->hdmi_enabled)
589        return;
590    exynos_gsc_destroy(dev->hdmi_gsc);
591    hdmi_stop_background(dev);
592    dev->hdmi_gsc = NULL;
593    dev->hdmi_enabled = false;
594}
595
596static int hdmi_configure_fblayer(struct exynos5_hwc_composer_device_1_t *dev,
597                                  hwc_layer_1_t &layer)
598{
599    int ret = 0;
600    exynos_gsc_img src_cfg, dst_cfg;
601    memset(&src_cfg, 0, sizeof(src_cfg));
602    memset(&dst_cfg, 0, sizeof(dst_cfg));
603    private_handle_t *h = private_handle_t::dynamicCast(layer.handle);
604
605    src_cfg.x = layer.sourceCrop.left;
606    src_cfg.y = layer.sourceCrop.top;
607    src_cfg.w = WIDTH(layer.sourceCrop);
608    src_cfg.fw = h->stride;
609    src_cfg.h = HEIGHT(layer.sourceCrop);
610    src_cfg.fh = h->vstride;
611    src_cfg.format = HAL_PIXEL_FORMAT_RGBX_8888;
612    src_cfg.yaddr = h->fd;
613    src_cfg.acquireFenceFd = layer.acquireFenceFd;
614
615    dst_cfg.w = dev->hdmi_w;
616    dst_cfg.fw = dev->hdmi_w;
617    dst_cfg.h = dev->hdmi_h;
618    dst_cfg.fh = dev->hdmi_h;
619    dst_cfg.format = HAL_PIXEL_FORMAT_EXYNOS_YV12;
620    dst_cfg.rot = layer.transform;
621
622    if (gsc_src_cfg_changed(src_cfg, dev->hdmi_src)
623            || gsc_dst_cfg_changed(dst_cfg, dev->hdmi_dst)) {
624
625        ALOGV("HDMI source config:");
626        dump_gsc_img(src_cfg);
627        ALOGV("HDMI dest config:");
628        dump_gsc_img(dst_cfg);
629
630        exynos_gsc_stop_exclusive(dev->hdmi_gsc);
631
632        ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_cfg, &dst_cfg);
633        if (ret < 0) {
634            ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret);
635            goto err;
636        }
637
638        dev->hdmi_src = src_cfg;
639        dev->hdmi_dst = dst_cfg;
640    }
641
642    ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_cfg, NULL);
643    if (ret < 0) {
644        ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret);
645        goto err;
646    }
647
648    layer.releaseFenceFd = src_cfg.releaseFenceFd;
649
650err:
651    if (layer.acquireFenceFd >= 0)
652        close(layer.acquireFenceFd);
653    return ret;
654}
655
656bool exynos5_is_offscreen(hwc_layer_1_t &layer,
657        struct exynos5_hwc_composer_device_1_t *pdev)
658{
659    return layer.sourceCrop.left > pdev->xres ||
660            layer.sourceCrop.right < 0 ||
661            layer.sourceCrop.top > pdev->yres ||
662            layer.sourceCrop.bottom < 0;
663}
664
665size_t exynos5_visible_width(hwc_layer_1_t &layer, int format,
666        struct exynos5_hwc_composer_device_1_t *pdev)
667{
668    int bpp;
669    if (exynos5_requires_gscaler(layer, format))
670        bpp = 32;
671    else
672        bpp = exynos5_format_to_bpp(format);
673    int left = max(layer.displayFrame.left, 0);
674    int right = min(layer.displayFrame.right, pdev->xres);
675
676    return (right - left) * bpp / 8;
677}
678
679bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i,
680        struct exynos5_hwc_composer_device_1_t *pdev)
681{
682    if (layer.flags & HWC_SKIP_LAYER) {
683        ALOGV("\tlayer %u: skipping", i);
684        return false;
685    }
686
687    private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
688
689    if (!handle) {
690        ALOGV("\tlayer %u: handle is NULL", i);
691        return false;
692    }
693    if (!exynos5_format_is_rgb(handle->format) &&
694            !exynos5_format_is_supported_by_gscaler(handle->format)) {
695        ALOGW("\tlayer %u: unexpected format %u", i, handle->format);
696        return false;
697    }
698
699    if (exynos5_requires_gscaler(layer, handle->format)) {
700        if (!exynos5_supports_gscaler(layer, handle->format, false)) {
701            ALOGV("\tlayer %u: gscaler required but not supported", i);
702            return false;
703        }
704    } else {
705        if (!exynos5_format_is_supported(handle->format)) {
706            ALOGV("\tlayer %u: pixel format %u not supported", i, handle->format);
707            return false;
708        }
709    }
710    if (!exynos5_blending_is_supported(layer.blending)) {
711        ALOGV("\tlayer %u: blending %d not supported", i, layer.blending);
712        return false;
713    }
714    if (CC_UNLIKELY(exynos5_is_offscreen(layer, pdev))) {
715        ALOGW("\tlayer %u: off-screen", i);
716        return false;
717    }
718    if (exynos5_visible_width(layer, handle->format, pdev) < BURSTLEN_BYTES) {
719        ALOGV("\tlayer %u: visible area is too narrow", i);
720        return false;
721    }
722
723    return true;
724}
725
726inline bool intersect(const hwc_rect &r1, const hwc_rect &r2)
727{
728    return !(r1.left > r2.right ||
729        r1.right < r2.left ||
730        r1.top > r2.bottom ||
731        r1.bottom < r2.top);
732}
733
734inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2)
735{
736    hwc_rect i;
737    i.top = max(r1.top, r2.top);
738    i.bottom = min(r1.bottom, r2.bottom);
739    i.left = max(r1.left, r2.left);
740    i.right = min(r1.right, r2.right);
741    return i;
742}
743
744static int exynos5_prepare_fimd(exynos5_hwc_composer_device_1_t *pdev,
745        hwc_display_contents_1_t* contents)
746{
747    ALOGV("preparing %u layers for FIMD", contents->numHwLayers);
748
749    memset(pdev->bufs.gsc_map, 0, sizeof(pdev->bufs.gsc_map));
750
751    bool force_fb = pdev->force_gpu;
752    for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
753        pdev->bufs.overlay_map[i] = -1;
754
755    bool fb_needed = false;
756    size_t first_fb = 0, last_fb = 0;
757
758    // find unsupported overlays
759    for (size_t i = 0; i < contents->numHwLayers; i++) {
760        hwc_layer_1_t &layer = contents->hwLayers[i];
761
762        if (layer.compositionType == HWC_FRAMEBUFFER_TARGET) {
763            ALOGV("\tlayer %u: framebuffer target", i);
764            continue;
765        }
766
767        if (layer.compositionType == HWC_BACKGROUND && !force_fb) {
768            ALOGV("\tlayer %u: background supported", i);
769            dump_layer(&contents->hwLayers[i]);
770            continue;
771        }
772
773        if (exynos5_supports_overlay(contents->hwLayers[i], i, pdev) &&
774                !force_fb) {
775            ALOGV("\tlayer %u: overlay supported", i);
776            layer.compositionType = HWC_OVERLAY;
777            dump_layer(&contents->hwLayers[i]);
778            continue;
779        }
780
781        if (!fb_needed) {
782            first_fb = i;
783            fb_needed = true;
784        }
785        last_fb = i;
786        layer.compositionType = HWC_FRAMEBUFFER;
787
788        dump_layer(&contents->hwLayers[i]);
789    }
790
791    // can't composite overlays sandwiched between framebuffers
792    if (fb_needed)
793        for (size_t i = first_fb; i < last_fb; i++)
794            contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
795
796    // Incrementally try to add our supported layers to hardware windows.
797    // If adding a layer would violate a hardware constraint, force it
798    // into the framebuffer and try again.  (Revisiting the entire list is
799    // necessary because adding a layer to the framebuffer can cause other
800    // windows to retroactively violate constraints.)
801    bool changed;
802    do {
803        android::Vector<hwc_rect> rects;
804        android::Vector<hwc_rect> overlaps;
805        size_t pixels_left, windows_left, gsc_left = NUM_GSC_UNITS;
806
807        if (fb_needed) {
808            hwc_rect_t fb_rect;
809            fb_rect.top = fb_rect.left = 0;
810            fb_rect.right = pdev->xres - 1;
811            fb_rect.bottom = pdev->yres - 1;
812            pixels_left = MAX_PIXELS - pdev->xres * pdev->yres;
813            windows_left = NUM_HW_WINDOWS - 1;
814            rects.push_back(fb_rect);
815        }
816        else {
817            pixels_left = MAX_PIXELS;
818            windows_left = NUM_HW_WINDOWS;
819        }
820        if (pdev->hdmi_enabled)
821            gsc_left--;
822
823        changed = false;
824
825        for (size_t i = 0; i < contents->numHwLayers; i++) {
826            hwc_layer_1_t &layer = contents->hwLayers[i];
827            if ((layer.flags & HWC_SKIP_LAYER) ||
828                    layer.compositionType == HWC_FRAMEBUFFER_TARGET)
829                continue;
830
831            private_handle_t *handle = private_handle_t::dynamicCast(
832                    layer.handle);
833
834            // we've already accounted for the framebuffer above
835            if (layer.compositionType == HWC_FRAMEBUFFER)
836                continue;
837
838            // only layer 0 can be HWC_BACKGROUND, so we can
839            // unconditionally allow it without extra checks
840            if (layer.compositionType == HWC_BACKGROUND) {
841                windows_left--;
842                continue;
843            }
844
845            size_t pixels_needed = WIDTH(layer.displayFrame) *
846                    HEIGHT(layer.displayFrame);
847            bool can_compose = windows_left && pixels_needed <= pixels_left;
848            bool gsc_required = exynos5_requires_gscaler(layer, handle->format);
849            if (gsc_required)
850                can_compose = can_compose && gsc_left;
851
852            // hwc_rect_t right and bottom values are normally exclusive;
853            // the intersection logic is simpler if we make them inclusive
854            hwc_rect_t visible_rect = layer.displayFrame;
855            visible_rect.right--; visible_rect.bottom--;
856
857            // no more than 2 layers can overlap on a given pixel
858            for (size_t j = 0; can_compose && j < overlaps.size(); j++) {
859                if (intersect(visible_rect, overlaps.itemAt(j)))
860                    can_compose = false;
861            }
862
863            if (!can_compose) {
864                layer.compositionType = HWC_FRAMEBUFFER;
865                if (!fb_needed) {
866                    first_fb = last_fb = i;
867                    fb_needed = true;
868                }
869                else {
870                    first_fb = min(i, first_fb);
871                    last_fb = max(i, last_fb);
872                }
873                changed = true;
874                break;
875            }
876
877            for (size_t j = 0; j < rects.size(); j++) {
878                const hwc_rect_t &other_rect = rects.itemAt(j);
879                if (intersect(visible_rect, other_rect))
880                    overlaps.push_back(intersection(visible_rect, other_rect));
881            }
882            rects.push_back(visible_rect);
883            pixels_left -= pixels_needed;
884            windows_left--;
885            if (gsc_required)
886                gsc_left--;
887        }
888
889        if (changed)
890            for (size_t i = first_fb; i < last_fb; i++)
891                contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
892    } while(changed);
893
894    unsigned int nextWindow = 0;
895    int nextGsc = 0;
896
897    for (size_t i = 0; i < contents->numHwLayers; i++) {
898        hwc_layer_1_t &layer = contents->hwLayers[i];
899
900        if (fb_needed && i == first_fb) {
901            ALOGV("assigning framebuffer to window %u\n",
902                    nextWindow);
903            nextWindow++;
904            continue;
905        }
906
907        if (layer.compositionType != HWC_FRAMEBUFFER &&
908                layer.compositionType != HWC_FRAMEBUFFER_TARGET) {
909            ALOGV("assigning layer %u to window %u", i, nextWindow);
910            pdev->bufs.overlay_map[nextWindow] = i;
911            if (layer.compositionType == HWC_OVERLAY) {
912                private_handle_t *handle =
913                        private_handle_t::dynamicCast(layer.handle);
914                if (exynos5_requires_gscaler(layer, handle->format)) {
915                    ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS[nextGsc]);
916                    pdev->bufs.gsc_map[nextWindow].mode =
917                            exynos5_gsc_map_t::GSC_M2M;
918                    pdev->bufs.gsc_map[nextWindow].idx = nextGsc++;
919                }
920            }
921            nextWindow++;
922        }
923    }
924
925    for (size_t i = nextGsc; i < NUM_GSC_UNITS; i++) {
926        for (size_t j = 0; j < NUM_GSC_DST_BUFS; j++)
927            if (pdev->gsc[i].dst_buf[j])
928                pdev->alloc_device->free(pdev->alloc_device,
929                        pdev->gsc[i].dst_buf[j]);
930        memset(&pdev->gsc[i], 0, sizeof(pdev->gsc[i]));
931    }
932
933    if (fb_needed)
934        pdev->bufs.fb_window = first_fb;
935    else
936        pdev->bufs.fb_window = NO_FB_NEEDED;
937
938    return 0;
939}
940
941static int exynos5_prepare_hdmi(exynos5_hwc_composer_device_1_t *pdev,
942        hwc_display_contents_1_t* contents)
943{
944    ALOGV("preparing %u layers for HDMI", contents->numHwLayers);
945
946    for (size_t i = 0; i < contents->numHwLayers; i++) {
947        hwc_layer_1_t &layer = contents->hwLayers[i];
948
949        if (layer.compositionType == HWC_FRAMEBUFFER_TARGET) {
950            ALOGV("\tlayer %u: framebuffer target", i);
951            dump_layer(&layer);
952            continue;
953        }
954
955        if (layer.compositionType == HWC_BACKGROUND) {
956            ALOGV("\tlayer %u: background layer", i);
957            dump_layer(&layer);
958            continue;
959        }
960
961        layer.compositionType = HWC_FRAMEBUFFER;
962        dump_layer(&layer);
963    }
964
965    return 0;
966}
967
968static int exynos5_prepare(hwc_composer_device_1_t *dev,
969        size_t numDisplays, hwc_display_contents_1_t** displays)
970{
971    if (!numDisplays || !displays)
972        return 0;
973
974    exynos5_hwc_composer_device_1_t *pdev =
975            (exynos5_hwc_composer_device_1_t *)dev;
976    hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
977    hwc_display_contents_1_t *hdmi_contents = displays[HWC_DISPLAY_EXTERNAL];
978
979    if (pdev->hdmi_hpd) {
980        hdmi_enable(pdev);
981    } else {
982        hdmi_disable(pdev);
983    }
984
985    if (fimd_contents) {
986        int err = exynos5_prepare_fimd(pdev, fimd_contents);
987        if (err)
988            return err;
989    }
990
991    if (hdmi_contents) {
992        int err = exynos5_prepare_hdmi(pdev, hdmi_contents);
993        if (err)
994            return err;
995    }
996
997    return 0;
998}
999
1000static int exynos5_config_gsc_m2m(hwc_layer_1_t &layer,
1001        alloc_device_t* alloc_device, exynos5_gsc_data_t *gsc_data,
1002        int gsc_idx)
1003{
1004    ALOGV("configuring gscaler %u for memory-to-memory", gsc_idx);
1005
1006    private_handle_t *src_handle = private_handle_t::dynamicCast(layer.handle);
1007    buffer_handle_t dst_buf;
1008    private_handle_t *dst_handle;
1009    int ret = 0;
1010
1011    exynos_gsc_img src_cfg, dst_cfg;
1012    memset(&src_cfg, 0, sizeof(src_cfg));
1013    memset(&dst_cfg, 0, sizeof(dst_cfg));
1014
1015    src_cfg.x = layer.sourceCrop.left;
1016    src_cfg.y = layer.sourceCrop.top;
1017    src_cfg.w = WIDTH(layer.sourceCrop);
1018    src_cfg.fw = src_handle->stride;
1019    src_cfg.h = HEIGHT(layer.sourceCrop);
1020    src_cfg.fh = src_handle->vstride;
1021    src_cfg.yaddr = src_handle->fd;
1022    if (exynos5_format_is_ycrcb(src_handle->format)) {
1023        src_cfg.uaddr = src_handle->fd2;
1024        src_cfg.vaddr = src_handle->fd1;
1025    } else {
1026        src_cfg.uaddr = src_handle->fd1;
1027        src_cfg.vaddr = src_handle->fd2;
1028    }
1029    src_cfg.format = src_handle->format;
1030    src_cfg.drmMode = !!(src_handle->flags & GRALLOC_USAGE_PROTECTED);
1031
1032    dst_cfg.x = 0;
1033    dst_cfg.y = 0;
1034    dst_cfg.w = WIDTH(layer.displayFrame);
1035    dst_cfg.h = HEIGHT(layer.displayFrame);
1036    dst_cfg.rot = layer.transform;
1037    dst_cfg.drmMode = src_cfg.drmMode;
1038    if (exynos5_format_is_rgb(src_handle->format) &&
1039            src_handle->format != HAL_PIXEL_FORMAT_RGB_565)
1040        dst_cfg.format = HAL_PIXEL_FORMAT_RGBX_8888;
1041    else
1042        dst_cfg.format = HAL_PIXEL_FORMAT_BGRA_8888;
1043    // RGBX8888 surfaces are already in the right color order from the GPU,
1044    // RGB565 and YUV surfaces need the Gscaler to swap R & B
1045
1046    ALOGV("source configuration:");
1047    dump_gsc_img(src_cfg);
1048
1049    if (gsc_src_cfg_changed(src_cfg, gsc_data->src_cfg) ||
1050            gsc_dst_cfg_changed(dst_cfg, gsc_data->dst_cfg)) {
1051        int dst_stride;
1052        int usage = GRALLOC_USAGE_SW_READ_NEVER |
1053                GRALLOC_USAGE_SW_WRITE_NEVER |
1054                GRALLOC_USAGE_HW_COMPOSER;
1055
1056        if (src_handle->flags & GRALLOC_USAGE_PROTECTED)
1057            usage |= GRALLOC_USAGE_PROTECTED;
1058
1059        int w = ALIGN(WIDTH(layer.displayFrame), GSC_W_ALIGNMENT);
1060        int h = ALIGN(HEIGHT(layer.displayFrame), GSC_H_ALIGNMENT);
1061
1062        for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) {
1063            if (gsc_data->dst_buf[i]) {
1064                alloc_device->free(alloc_device, gsc_data->dst_buf[i]);
1065                gsc_data->dst_buf[i] = NULL;
1066            }
1067
1068            int ret = alloc_device->alloc(alloc_device, w, h,
1069                    HAL_PIXEL_FORMAT_RGBX_8888, usage, &gsc_data->dst_buf[i],
1070                    &dst_stride);
1071            if (ret < 0) {
1072                ALOGE("failed to allocate destination buffer: %s",
1073                        strerror(-ret));
1074                goto err_alloc;
1075            }
1076        }
1077
1078        gsc_data->current_buf = 0;
1079    }
1080
1081    dst_buf = gsc_data->dst_buf[gsc_data->current_buf];
1082    dst_handle = private_handle_t::dynamicCast(dst_buf);
1083
1084    dst_cfg.fw = dst_handle->stride;
1085    dst_cfg.fh = dst_handle->vstride;
1086    dst_cfg.yaddr = dst_handle->fd;
1087
1088    ALOGV("destination configuration:");
1089    dump_gsc_img(dst_cfg);
1090
1091    gsc_data->gsc = exynos_gsc_create_exclusive(AVAILABLE_GSC_UNITS[gsc_idx],
1092            GSC_M2M_MODE, GSC_DUMMY);
1093    if (!gsc_data->gsc) {
1094        ALOGE("failed to create gscaler handle");
1095        ret = -1;
1096        goto err_alloc;
1097    }
1098
1099    ret = exynos_gsc_config_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg);
1100    if (ret < 0) {
1101        ALOGE("failed to configure gscaler %u", gsc_idx);
1102        goto err_gsc_config;
1103    }
1104
1105    ret = exynos_gsc_run_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg);
1106    if (ret < 0) {
1107        ALOGE("failed to run gscaler %u", gsc_idx);
1108        goto err_gsc_config;
1109    }
1110
1111    gsc_data->src_cfg = src_cfg;
1112    gsc_data->dst_cfg = dst_cfg;
1113
1114    return 0;
1115
1116err_gsc_config:
1117    exynos_gsc_destroy(gsc_data->gsc);
1118    gsc_data->gsc = NULL;
1119err_alloc:
1120    for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) {
1121        if (gsc_data->dst_buf[i]) {
1122           alloc_device->free(alloc_device, gsc_data->dst_buf[i]);
1123           gsc_data->dst_buf[i] = NULL;
1124       }
1125    }
1126    memset(&gsc_data->src_cfg, 0, sizeof(gsc_data->src_cfg));
1127    memset(&gsc_data->dst_cfg, 0, sizeof(gsc_data->dst_cfg));
1128    return ret;
1129}
1130
1131static void exynos5_config_handle(private_handle_t *handle,
1132        hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame,
1133        int32_t blending, int fence_fd, s3c_fb_win_config &cfg,
1134        exynos5_hwc_composer_device_1_t *pdev)
1135{
1136    uint32_t x, y;
1137    uint32_t w = WIDTH(displayFrame);
1138    uint32_t h = HEIGHT(displayFrame);
1139    uint8_t bpp = exynos5_format_to_bpp(handle->format);
1140    uint32_t offset = (sourceCrop.top * handle->stride + sourceCrop.left) * bpp / 8;
1141
1142    if (displayFrame.left < 0) {
1143        unsigned int crop = -displayFrame.left;
1144        ALOGV("layer off left side of screen; cropping %u pixels from left edge",
1145                crop);
1146        x = 0;
1147        w -= crop;
1148        offset += crop * bpp / 8;
1149    } else {
1150        x = displayFrame.left;
1151    }
1152
1153    if (displayFrame.right > pdev->xres) {
1154        unsigned int crop = displayFrame.right - pdev->xres;
1155        ALOGV("layer off right side of screen; cropping %u pixels from right edge",
1156                crop);
1157        w -= crop;
1158    }
1159
1160    if (displayFrame.top < 0) {
1161        unsigned int crop = -displayFrame.top;
1162        ALOGV("layer off top side of screen; cropping %u pixels from top edge",
1163                crop);
1164        y = 0;
1165        h -= crop;
1166        offset += handle->stride * crop * bpp / 8;
1167    } else {
1168        y = displayFrame.top;
1169    }
1170
1171    if (displayFrame.bottom > pdev->yres) {
1172        int crop = displayFrame.bottom - pdev->yres;
1173        ALOGV("layer off bottom side of screen; cropping %u pixels from bottom edge",
1174                crop);
1175        h -= crop;
1176    }
1177
1178    cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER;
1179    cfg.fd = handle->fd;
1180    cfg.x = x;
1181    cfg.y = y;
1182    cfg.w = w;
1183    cfg.h = h;
1184    cfg.format = exynos5_format_to_s3c_format(handle->format);
1185    cfg.offset = offset;
1186    cfg.stride = handle->stride * bpp / 8;
1187    cfg.blending = exynos5_blending_to_s3c_blending(blending);
1188    cfg.fence_fd = fence_fd;
1189}
1190
1191static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg,
1192        exynos5_hwc_composer_device_1_t *pdev)
1193{
1194    if (layer->compositionType == HWC_BACKGROUND) {
1195        hwc_color_t color = layer->backgroundColor;
1196        cfg.state = cfg.S3C_FB_WIN_STATE_COLOR;
1197        cfg.color = (color.r << 16) | (color.g << 8) | color.b;
1198        cfg.x = 0;
1199        cfg.y = 0;
1200        cfg.w = pdev->xres;
1201        cfg.h = pdev->yres;
1202        return;
1203    }
1204
1205    private_handle_t *handle = private_handle_t::dynamicCast(layer->handle);
1206    exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame,
1207            layer->blending, layer->acquireFenceFd, cfg, pdev);
1208}
1209
1210static int exynos5_post_fimd(exynos5_hwc_composer_device_1_t *pdev,
1211        hwc_display_contents_1_t* contents)
1212{
1213    exynos5_hwc_post_data_t *pdata = &pdev->bufs;
1214    struct s3c_fb_win_config_data win_data;
1215    struct s3c_fb_win_config *config = win_data.config;
1216
1217    memset(config, 0, sizeof(win_data.config));
1218    for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
1219        config[i].fence_fd = -1;
1220
1221    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
1222        int layer_idx = pdata->overlay_map[i];
1223        if (layer_idx != -1) {
1224            hwc_layer_1_t &layer = contents->hwLayers[layer_idx];
1225            private_handle_t *handle =
1226                    private_handle_t::dynamicCast(layer.handle);
1227
1228            if (pdata->gsc_map[i].mode == exynos5_gsc_map_t::GSC_M2M) {
1229                int gsc_idx = pdata->gsc_map[i].idx;
1230                exynos5_gsc_data_t &gsc = pdev->gsc[gsc_idx];
1231
1232                if (layer.acquireFenceFd != -1) {
1233                    int err = sync_wait(layer.acquireFenceFd, 100);
1234                    if (err != 0)
1235                        ALOGW("fence for layer %zu didn't signal in 100 ms: %s",
1236                              i, strerror(errno));
1237                    close(layer.acquireFenceFd);
1238                }
1239
1240                int err = exynos5_config_gsc_m2m(layer, pdev->alloc_device, &gsc,
1241                        gsc_idx);
1242                if (err < 0) {
1243                    ALOGE("failed to queue gscaler %u input for layer %u",
1244                            gsc_idx, i);
1245                    continue;
1246                }
1247
1248                err = exynos_gsc_stop_exclusive(gsc.gsc);
1249                exynos_gsc_destroy(gsc.gsc);
1250                gsc.gsc = NULL;
1251                if (err < 0) {
1252                    ALOGE("failed to dequeue gscaler output for layer %u", i);
1253                    continue;
1254                }
1255
1256                buffer_handle_t dst_buf = gsc.dst_buf[gsc.current_buf];
1257                gsc.current_buf = (gsc.current_buf + 1) % NUM_GSC_DST_BUFS;
1258                private_handle_t *dst_handle =
1259                        private_handle_t::dynamicCast(dst_buf);
1260                hwc_rect_t sourceCrop = { 0, 0,
1261                        WIDTH(layer.displayFrame), HEIGHT(layer.displayFrame) };
1262                exynos5_config_handle(dst_handle, sourceCrop,
1263                        layer.displayFrame, layer.blending, -1, config[i],
1264                        pdev);
1265            } else {
1266                exynos5_config_overlay(&layer, config[i], pdev);
1267            }
1268        }
1269        if (i == 0 && config[i].blending != S3C_FB_BLENDING_NONE) {
1270            ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
1271            config[i].blending = S3C_FB_BLENDING_NONE;
1272        }
1273
1274        ALOGV("window %u configuration:", i);
1275        dump_config(config[i]);
1276    }
1277
1278    int ret = ioctl(pdev->fd, S3CFB_WIN_CONFIG, &win_data);
1279    for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
1280        if (config[i].fence_fd != -1)
1281            close(config[i].fence_fd);
1282    if (ret < 0) {
1283        ALOGE("ioctl S3CFB_WIN_CONFIG failed: %s", strerror(errno));
1284        return ret;
1285    }
1286
1287    memcpy(pdev->last_config, &win_data.config, sizeof(win_data.config));
1288    memcpy(pdev->last_gsc_map, pdata->gsc_map, sizeof(pdata->gsc_map));
1289    pdev->last_fb_window = pdata->fb_window;
1290    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
1291        int layer_idx = pdata->overlay_map[i];
1292        if (layer_idx != -1) {
1293            hwc_layer_1_t &layer = contents->hwLayers[layer_idx];
1294            pdev->last_handles[i] = layer.handle;
1295        }
1296    }
1297
1298    return win_data.fence;
1299}
1300
1301static int exynos5_set_fimd(exynos5_hwc_composer_device_1_t *pdev,
1302        hwc_display_contents_1_t* contents)
1303{
1304    if (!contents->dpy || !contents->sur)
1305        return 0;
1306
1307    hwc_layer_1_t *fb_layer = NULL;
1308
1309    if (pdev->bufs.fb_window != NO_FB_NEEDED) {
1310        for (size_t i = 0; i < contents->numHwLayers; i++) {
1311            if (contents->hwLayers[i].compositionType ==
1312                    HWC_FRAMEBUFFER_TARGET) {
1313                pdev->bufs.overlay_map[pdev->bufs.fb_window] = i;
1314                fb_layer = &contents->hwLayers[i];
1315                break;
1316            }
1317        }
1318
1319        if (CC_UNLIKELY(!fb_layer)) {
1320            ALOGE("framebuffer target expected, but not provided");
1321            return -EINVAL;
1322        }
1323
1324        ALOGV("framebuffer target buffer:");
1325        dump_layer(fb_layer);
1326    }
1327
1328    int fence = exynos5_post_fimd(pdev, contents);
1329    if (fence < 0)
1330        return fence;
1331
1332    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
1333        if (pdev->bufs.overlay_map[i] != -1) {
1334            hwc_layer_1_t &layer =
1335                    contents->hwLayers[pdev->bufs.overlay_map[i]];
1336            int dup_fd = dup(fence);
1337            if (dup_fd < 0)
1338                ALOGW("release fence dup failed: %s", strerror(errno));
1339            layer.releaseFenceFd = dup_fd;
1340        }
1341    }
1342    close(fence);
1343
1344    return 0;
1345}
1346
1347static int exynos5_set_hdmi(exynos5_hwc_composer_device_1_t *pdev,
1348        hwc_display_contents_1_t* contents)
1349{
1350    if (!pdev->hdmi_enabled) {
1351        for (size_t i = 0; i < contents->numHwLayers; i++) {
1352            hwc_layer_1_t &layer = contents->hwLayers[i];
1353            if (layer.acquireFenceFd != -1)
1354                close(layer.acquireFenceFd);
1355        }
1356        return 0;
1357    }
1358
1359    for (size_t i = 0; i < contents->numHwLayers; i++) {
1360        hwc_layer_1_t &layer = contents->hwLayers[i];
1361
1362        if (layer.compositionType == HWC_FRAMEBUFFER_TARGET) {
1363            if (!layer.handle)
1364                continue;
1365
1366            ALOGV("HDMI FB layer:");
1367            dump_layer(&layer);
1368
1369            hdmi_configure_fblayer(pdev, layer);
1370        }
1371    }
1372
1373    return 0;
1374}
1375
1376static int exynos5_set(struct hwc_composer_device_1 *dev,
1377        size_t numDisplays, hwc_display_contents_1_t** displays)
1378{
1379    if (!numDisplays || !displays)
1380        return 0;
1381
1382    exynos5_hwc_composer_device_1_t *pdev =
1383            (exynos5_hwc_composer_device_1_t *)dev;
1384    hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
1385    hwc_display_contents_1_t *hdmi_contents = displays[HWC_DISPLAY_EXTERNAL];
1386
1387    if (fimd_contents) {
1388        int err = exynos5_set_fimd(pdev, fimd_contents);
1389        if (err)
1390            return err;
1391    }
1392
1393    if (hdmi_contents) {
1394        int err = exynos5_set_hdmi(pdev, hdmi_contents);
1395        if (err)
1396            return err;
1397    }
1398
1399    return 0;
1400}
1401
1402static void exynos5_registerProcs(struct hwc_composer_device_1* dev,
1403        hwc_procs_t const* procs)
1404{
1405    struct exynos5_hwc_composer_device_1_t* pdev =
1406            (struct exynos5_hwc_composer_device_1_t*)dev;
1407    pdev->procs = procs;
1408}
1409
1410static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
1411{
1412    struct exynos5_hwc_composer_device_1_t *pdev =
1413            (struct exynos5_hwc_composer_device_1_t *)dev;
1414
1415    switch (what) {
1416    case HWC_BACKGROUND_LAYER_SUPPORTED:
1417        // we support the background layer
1418        value[0] = 1;
1419        break;
1420    case HWC_VSYNC_PERIOD:
1421        // vsync period in nanosecond
1422        value[0] = pdev->vsync_period;
1423        break;
1424    default:
1425        // unsupported query
1426        return -EINVAL;
1427    }
1428    return 0;
1429}
1430
1431static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int dpy,
1432        int event, int enabled)
1433{
1434    struct exynos5_hwc_composer_device_1_t *pdev =
1435            (struct exynos5_hwc_composer_device_1_t *)dev;
1436
1437    switch (event) {
1438    case HWC_EVENT_VSYNC:
1439        __u32 val = !!enabled;
1440        int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val);
1441        if (err < 0) {
1442            ALOGE("vsync ioctl failed");
1443            return -errno;
1444        }
1445
1446        return 0;
1447    }
1448
1449    return -EINVAL;
1450}
1451
1452static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
1453        const char *buff, int len)
1454{
1455    const char *s = buff;
1456    s += strlen(s) + 1;
1457
1458    while (*s) {
1459        if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1460            pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
1461
1462        s += strlen(s) + 1;
1463        if (s - buff >= len)
1464            break;
1465    }
1466
1467    if (pdev->hdmi_hpd) {
1468        if (hdmi_get_config(pdev)) {
1469            ALOGE("Error reading HDMI configuration");
1470            pdev->hdmi_hpd = false;
1471            return;
1472        }
1473    }
1474
1475    ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
1476    if (pdev->hdmi_hpd)
1477        ALOGI("HDMI Resolution changed to %dx%d", pdev->hdmi_h, pdev->hdmi_w);
1478
1479    /* hwc_dev->procs is set right after the device is opened, but there is
1480     * still a race condition where a hotplug event might occur after the open
1481     * but before the procs are registered. */
1482    if (pdev->procs)
1483        pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, pdev->hdmi_hpd);
1484}
1485
1486static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev)
1487{
1488    if (!pdev->procs)
1489        return;
1490
1491    int err = lseek(pdev->vsync_fd, 0, SEEK_SET);
1492    if (err < 0) {
1493        ALOGE("error seeking to vsync timestamp: %s", strerror(errno));
1494        return;
1495    }
1496
1497    char buf[4096];
1498    err = read(pdev->vsync_fd, buf, sizeof(buf));
1499    if (err < 0) {
1500        ALOGE("error reading vsync timestamp: %s", strerror(errno));
1501        return;
1502    }
1503    buf[sizeof(buf) - 1] = '\0';
1504
1505    errno = 0;
1506    uint64_t timestamp = strtoull(buf, NULL, 0);
1507    if (!errno)
1508        pdev->procs->vsync(pdev->procs, 0, timestamp);
1509}
1510
1511static void *hwc_vsync_thread(void *data)
1512{
1513    struct exynos5_hwc_composer_device_1_t *pdev =
1514            (struct exynos5_hwc_composer_device_1_t *)data;
1515    char uevent_desc[4096];
1516    memset(uevent_desc, 0, sizeof(uevent_desc));
1517
1518    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
1519
1520    uevent_init();
1521
1522    char temp[4096];
1523    int err = read(pdev->vsync_fd, temp, sizeof(temp));
1524    if (err < 0) {
1525        ALOGE("error reading vsync timestamp: %s", strerror(errno));
1526        return NULL;
1527    }
1528
1529    struct pollfd fds[2];
1530    fds[0].fd = pdev->vsync_fd;
1531    fds[0].events = POLLPRI;
1532    fds[1].fd = uevent_get_fd();
1533    fds[1].events = POLLIN;
1534
1535    while (true) {
1536        int err = poll(fds, 2, -1);
1537
1538        if (err > 0) {
1539            if (fds[0].revents & POLLPRI) {
1540                handle_vsync_event(pdev);
1541            }
1542            else if (fds[1].revents & POLLIN) {
1543                int len = uevent_next_event(uevent_desc,
1544                        sizeof(uevent_desc) - 2);
1545
1546                bool hdmi = !strcmp(uevent_desc,
1547                        "change@/devices/virtual/switch/hdmi");
1548                if (hdmi)
1549                    handle_hdmi_uevent(pdev, uevent_desc, len);
1550            }
1551        }
1552        else if (err == -1) {
1553            if (errno == EINTR)
1554                break;
1555            ALOGE("error in vsync thread: %s", strerror(errno));
1556        }
1557    }
1558
1559    return NULL;
1560}
1561
1562static int exynos5_blank(struct hwc_composer_device_1 *dev, int dpy, int blank)
1563{
1564    struct exynos5_hwc_composer_device_1_t *pdev =
1565            (struct exynos5_hwc_composer_device_1_t *)dev;
1566
1567    int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
1568    int err = ioctl(pdev->fd, FBIOBLANK, fb_blank);
1569    if (err < 0) {
1570        if (errno == EBUSY)
1571            ALOGI("%sblank ioctl failed (display already %sblanked)",
1572                    blank ? "" : "un", blank ? "" : "un");
1573        else
1574            ALOGE("%sblank ioctl failed: %s", blank ? "" : "un",
1575                    strerror(errno));
1576        return -errno;
1577    }
1578
1579    if (pdev->hdmi_hpd) {
1580        if (blank && !pdev->hdmi_blanked)
1581            hdmi_disable(pdev);
1582        pdev->hdmi_blanked = !!blank;
1583    }
1584
1585    return 0;
1586}
1587
1588static void exynos5_dump(hwc_composer_device_1* dev, char *buff, int buff_len)
1589{
1590    if (buff_len <= 0)
1591        return;
1592
1593    struct exynos5_hwc_composer_device_1_t *pdev =
1594            (struct exynos5_hwc_composer_device_1_t *)dev;
1595
1596    android::String8 result;
1597
1598    result.appendFormat("  hdmi_enabled=%u\n", pdev->hdmi_enabled);
1599    if (pdev->hdmi_enabled)
1600        result.appendFormat("    w=%u, h=%u\n", pdev->hdmi_w, pdev->hdmi_h);
1601    result.append(
1602            "   type   |  handle  |  color   | blend | format |   position    |     size      | gsc \n"
1603            "----------+----------|----------+-------+--------+---------------+---------------------\n");
1604    //        8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
1605
1606    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
1607        struct s3c_fb_win_config &config = pdev->last_config[i];
1608        if (config.state == config.S3C_FB_WIN_STATE_DISABLED) {
1609            result.appendFormat(" %8s | %8s | %8s | %5s | %6s | %13s | %13s",
1610                    "DISABLED", "-", "-", "-", "-", "-", "-");
1611        }
1612        else {
1613            if (config.state == config.S3C_FB_WIN_STATE_COLOR)
1614                result.appendFormat(" %8s | %8s | %8x | %5s | %6s", "COLOR",
1615                        "-", config.color, "-", "-");
1616            else
1617                result.appendFormat(" %8s | %8x | %8s | %5x | %6x",
1618                        pdev->last_fb_window == i ? "FB" : "OVERLAY",
1619                        intptr_t(pdev->last_handles[i]),
1620                        "-", config.blending, config.format);
1621
1622            result.appendFormat(" | [%5d,%5d] | [%5u,%5u]", config.x, config.y,
1623                    config.w, config.h);
1624        }
1625        if (pdev->last_gsc_map[i].mode == exynos5_gsc_map_t::GSC_NONE)
1626            result.appendFormat(" | %3s", "-");
1627        else
1628            result.appendFormat(" | %3d",
1629                    AVAILABLE_GSC_UNITS[pdev->last_gsc_map[i].idx]);
1630        result.append("\n");
1631    }
1632
1633    strlcpy(buff, result.string(), buff_len);
1634}
1635
1636static int exynos5_getDisplayConfigs(struct hwc_composer_device_1 *dev,
1637        int disp, uint32_t *configs, size_t *numConfigs)
1638{
1639    struct exynos5_hwc_composer_device_1_t *pdev =
1640               (struct exynos5_hwc_composer_device_1_t *)dev;
1641
1642    if (*numConfigs == 0)
1643        return 0;
1644
1645    if (disp == HWC_DISPLAY_PRIMARY) {
1646        configs[0] = 0;
1647        *numConfigs = 1;
1648        return 0;
1649    } else if (disp == HWC_DISPLAY_EXTERNAL) {
1650        if (!pdev->hdmi_hpd) {
1651            return -EINVAL;
1652        }
1653
1654        int err = hdmi_get_config(pdev);
1655        if (err) {
1656            return -EINVAL;
1657        }
1658
1659        configs[0] = 0;
1660        *numConfigs = 1;
1661        return 0;
1662    }
1663
1664    return -EINVAL;
1665}
1666
1667static int32_t exynos5_fimd_attribute(struct exynos5_hwc_composer_device_1_t *pdev,
1668        const uint32_t attribute)
1669{
1670    switch(attribute) {
1671    case HWC_DISPLAY_VSYNC_PERIOD:
1672        return pdev->vsync_period;
1673
1674    case HWC_DISPLAY_WIDTH:
1675        return pdev->xres;
1676
1677    case HWC_DISPLAY_HEIGHT:
1678        return pdev->yres;
1679
1680    case HWC_DISPLAY_DPI_X:
1681        return pdev->xdpi;
1682
1683    case HWC_DISPLAY_DPI_Y:
1684        return pdev->ydpi;
1685
1686    default:
1687        ALOGE("unknown display attribute %u", attribute);
1688        return -EINVAL;
1689    }
1690}
1691
1692static int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t *pdev,
1693        const uint32_t attribute)
1694{
1695    switch(attribute) {
1696    case HWC_DISPLAY_VSYNC_PERIOD:
1697        return pdev->vsync_period;
1698
1699    case HWC_DISPLAY_WIDTH:
1700        return pdev->hdmi_w;
1701
1702    case HWC_DISPLAY_HEIGHT:
1703        return pdev->hdmi_h;
1704
1705    case HWC_DISPLAY_DPI_X:
1706    case HWC_DISPLAY_DPI_Y:
1707        return 0; // unknown
1708
1709    default:
1710        ALOGE("unknown display attribute %u", attribute);
1711        return -EINVAL;
1712    }
1713}
1714
1715static int exynos5_getDisplayAttributes(struct hwc_composer_device_1 *dev,
1716        int disp, uint32_t config, const uint32_t *attributes, int32_t *values)
1717{
1718    struct exynos5_hwc_composer_device_1_t *pdev =
1719                   (struct exynos5_hwc_composer_device_1_t *)dev;
1720
1721    for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
1722        if (disp == HWC_DISPLAY_PRIMARY)
1723            values[i] = exynos5_fimd_attribute(pdev, attributes[i]);
1724        else if (disp == HWC_DISPLAY_EXTERNAL)
1725            values[i] = exynos5_hdmi_attribute(pdev, attributes[i]);
1726        else {
1727            ALOGE("unknown display type %u", disp);
1728            return -EINVAL;
1729        }
1730    }
1731
1732    return 0;
1733}
1734
1735static int exynos5_close(hw_device_t* device);
1736
1737static int exynos5_open(const struct hw_module_t *module, const char *name,
1738        struct hw_device_t **device)
1739{
1740    int ret;
1741    int refreshRate;
1742    int sw_fd;
1743
1744    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1745        return -EINVAL;
1746    }
1747
1748    struct exynos5_hwc_composer_device_1_t *dev;
1749    dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev));
1750    memset(dev, 0, sizeof(*dev));
1751
1752    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
1753            (const struct hw_module_t **)&dev->gralloc_module)) {
1754        ALOGE("failed to get gralloc hw module");
1755        ret = -EINVAL;
1756        goto err_get_module;
1757    }
1758
1759    if (gralloc_open((const hw_module_t *)dev->gralloc_module,
1760            &dev->alloc_device)) {
1761        ALOGE("failed to open gralloc");
1762        ret = -EINVAL;
1763        goto err_get_module;
1764    }
1765
1766    dev->fd = open("/dev/graphics/fb0", O_RDWR);
1767    if (dev->fd < 0) {
1768        ALOGE("failed to open framebuffer");
1769        ret = dev->fd;
1770        goto err_open_fb;
1771    }
1772
1773    struct fb_var_screeninfo info;
1774    if (ioctl(dev->fd, FBIOGET_VSCREENINFO, &info) == -1) {
1775        ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno));
1776        ret = -errno;
1777        goto err_ioctl;
1778    }
1779
1780    refreshRate = 1000000000000LLU /
1781        (
1782         uint64_t( info.upper_margin + info.lower_margin + info.yres )
1783         * ( info.left_margin  + info.right_margin + info.xres )
1784         * info.pixclock
1785        );
1786
1787    if (refreshRate == 0) {
1788        ALOGW("invalid refresh rate, assuming 60 Hz");
1789        refreshRate = 60;
1790    }
1791
1792    dev->xres = 2560;
1793    dev->yres = 1600;
1794    dev->xdpi = 1000 * (info.xres * 25.4f) / info.width;
1795    dev->ydpi = 1000 * (info.yres * 25.4f) / info.height;
1796    dev->vsync_period  = 1000000000 / refreshRate;
1797
1798    ALOGV("using\n"
1799          "xres         = %d px\n"
1800          "yres         = %d px\n"
1801          "width        = %d mm (%f dpi)\n"
1802          "height       = %d mm (%f dpi)\n"
1803          "refresh rate = %d Hz\n",
1804          dev->xres, dev->yres, info.width, dev->xdpi / 1000.0,
1805          info.height, dev->ydpi / 1000.0, refreshRate);
1806
1807    dev->hdmi_mixer0 = open("/dev/v4l-subdev7", O_RDWR);
1808    if (dev->hdmi_layer0 < 0) {
1809        ALOGE("failed to open hdmi mixer0 subdev");
1810        ret = dev->hdmi_layer0;
1811        goto err_ioctl;
1812    }
1813
1814    dev->hdmi_layer0 = open("/dev/video16", O_RDWR);
1815    if (dev->hdmi_layer0 < 0) {
1816        ALOGE("failed to open hdmi layer0 device");
1817        ret = dev->hdmi_layer0;
1818        goto err_mixer0;
1819    }
1820
1821    dev->hdmi_layer1 = open("/dev/video17", O_RDWR);
1822    if (dev->hdmi_layer1 < 0) {
1823        ALOGE("failed to open hdmi layer1 device");
1824        ret = dev->hdmi_layer1;
1825        goto err_hdmi0;
1826    }
1827
1828    dev->vsync_fd = open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY);
1829    if (dev->vsync_fd < 0) {
1830        ALOGE("failed to open vsync attribute");
1831        ret = dev->vsync_fd;
1832        goto err_hdmi1;
1833    }
1834
1835    sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
1836    if (sw_fd) {
1837        char val;
1838        if (read(sw_fd, &val, 1) == 1 && val == '1') {
1839            dev->hdmi_hpd = true;
1840            if (hdmi_get_config(dev)) {
1841                ALOGE("Error reading HDMI configuration");
1842                dev->hdmi_hpd = false;
1843            }
1844        }
1845    }
1846
1847    dev->base.common.tag = HARDWARE_DEVICE_TAG;
1848    dev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
1849    dev->base.common.module = const_cast<hw_module_t *>(module);
1850    dev->base.common.close = exynos5_close;
1851
1852    dev->base.prepare = exynos5_prepare;
1853    dev->base.set = exynos5_set;
1854    dev->base.eventControl = exynos5_eventControl;
1855    dev->base.blank = exynos5_blank;
1856    dev->base.query = exynos5_query;
1857    dev->base.registerProcs = exynos5_registerProcs;
1858    dev->base.dump = exynos5_dump;
1859    dev->base.getDisplayConfigs = exynos5_getDisplayConfigs;
1860    dev->base.getDisplayAttributes = exynos5_getDisplayAttributes;
1861
1862    *device = &dev->base.common;
1863
1864    ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
1865    if (ret) {
1866        ALOGE("failed to start vsync thread: %s", strerror(ret));
1867        ret = -ret;
1868        goto err_vsync;
1869    }
1870
1871    char value[PROPERTY_VALUE_MAX];
1872    property_get("debug.hwc.force_gpu", value, "0");
1873    dev->force_gpu = atoi(value);
1874
1875    return 0;
1876
1877err_vsync:
1878    close(dev->vsync_fd);
1879err_mixer0:
1880    close(dev->hdmi_mixer0);
1881err_hdmi1:
1882    close(dev->hdmi_layer0);
1883err_hdmi0:
1884    close(dev->hdmi_layer1);
1885err_ioctl:
1886    close(dev->fd);
1887err_open_fb:
1888    gralloc_close(dev->alloc_device);
1889err_get_module:
1890    free(dev);
1891    return ret;
1892}
1893
1894static int exynos5_close(hw_device_t *device)
1895{
1896    struct exynos5_hwc_composer_device_1_t *dev =
1897            (struct exynos5_hwc_composer_device_1_t *)device;
1898    pthread_kill(dev->vsync_thread, SIGTERM);
1899    pthread_join(dev->vsync_thread, NULL);
1900    for (size_t i = 0; i < NUM_GSC_UNITS; i++) {
1901        if (dev->gsc[i].gsc)
1902            exynos_gsc_destroy(dev->gsc[i].gsc);
1903        for (size_t j = 0; i < NUM_GSC_DST_BUFS; j++)
1904            if (dev->gsc[i].dst_buf[j])
1905                dev->alloc_device->free(dev->alloc_device, dev->gsc[i].dst_buf[j]);
1906    }
1907    gralloc_close(dev->alloc_device);
1908    close(dev->vsync_fd);
1909    close(dev->hdmi_mixer0);
1910    close(dev->hdmi_layer0);
1911    close(dev->hdmi_layer1);
1912    close(dev->fd);
1913    return 0;
1914}
1915
1916static struct hw_module_methods_t exynos5_hwc_module_methods = {
1917    open: exynos5_open,
1918};
1919
1920hwc_module_t HAL_MODULE_INFO_SYM = {
1921    common: {
1922        tag: HARDWARE_MODULE_TAG,
1923        module_api_version: HWC_MODULE_API_VERSION_0_1,
1924        hal_api_version: HARDWARE_HAL_API_VERSION,
1925        id: HWC_HARDWARE_MODULE_ID,
1926        name: "Samsung exynos5 hwcomposer module",
1927        author: "Google",
1928        methods: &exynos5_hwc_module_methods,
1929    }
1930};
1931