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