hwc.cpp revision 77cbbd6fb8086c0e9f39781fcb883d5e5693f84d
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/log.h>
35#include <hardware/gralloc.h>
36#include <hardware/hardware.h>
37#include <hardware/hwcomposer.h>
38#include <hardware_legacy/uevent.h>
39#include <utils/Vector.h>
40
41#include <sync/sync.h>
42
43#include "ion.h"
44#include "gralloc_priv.h"
45#include "exynos_gscaler.h"
46#include "exynos_format.h"
47#include "videodev2.h"
48
49struct hwc_callback_entry {
50    void (*callback)(void *, private_handle_t *);
51    void *data;
52};
53typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t;
54
55const size_t NUM_HW_WINDOWS = 5;
56const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
57const size_t MAX_PIXELS = 2560 * 1600 * 2;
58const size_t NUM_GSC_UNITS = 4;
59const size_t GSC_W_ALIGNMENT = 16;
60const size_t GSC_H_ALIGNMENT = 16;
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    exynos5_hwc_composer_device_1_t *pdev;
75    int                             overlay_map[NUM_HW_WINDOWS];
76    exynos5_gsc_map_t               gsc_map[NUM_HW_WINDOWS];
77    hwc_layer_1_t                   overlays[NUM_HW_WINDOWS];
78    int                             num_overlays;
79    size_t                          fb_window;
80    int                             fence;
81    pthread_mutex_t                 completion_lock;
82    pthread_cond_t                  completion;
83};
84
85const size_t NUM_GSC_DST_BUFS = 2;
86struct exynos5_gsc_data_t {
87    void            *gsc;
88    exynos_gsc_img  src_cfg;
89    exynos_gsc_img  dst_cfg;
90    buffer_handle_t dst_buf[NUM_GSC_DST_BUFS];
91    size_t          current_buf;
92};
93
94struct exynos5_hwc_composer_device_1_t {
95    hwc_composer_device_1_t base;
96
97    int                     fd;
98    int                     vsync_fd;
99    exynos5_hwc_post_data_t bufs;
100
101    const private_module_t  *gralloc_module;
102    alloc_device_t          *alloc_device;
103    hwc_procs_t             *procs;
104    pthread_t               vsync_thread;
105
106    int  hdmi_fd;
107    bool hdmi_hpd;
108    bool hdmi_mirroring;
109    void *hdmi_gsc;
110    exynos_gsc_img hdmi_cfg;
111
112    exynos5_gsc_data_t      gsc[NUM_GSC_UNITS];
113};
114
115static void dump_handle(private_handle_t *h)
116{
117    ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u",
118            h->format, h->width, h->height, h->stride);
119}
120
121static void dump_layer(hwc_layer_1_t const *l)
122{
123    ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
124            "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
125            l->compositionType, l->flags, l->handle, l->transform,
126            l->blending,
127            l->sourceCrop.left,
128            l->sourceCrop.top,
129            l->sourceCrop.right,
130            l->sourceCrop.bottom,
131            l->displayFrame.left,
132            l->displayFrame.top,
133            l->displayFrame.right,
134            l->displayFrame.bottom);
135
136    if(l->handle && !(l->flags & HWC_SKIP_LAYER))
137        dump_handle(private_handle_t::dynamicCast(l->handle));
138}
139
140static void dump_config(s3c_fb_win_config &c)
141{
142    ALOGV("\tstate = %u", c.state);
143    if (c.state == c.S3C_FB_WIN_STATE_BUFFER) {
144        ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
145                "x = %d, y = %d, w = %u, h = %u, "
146                "format = %u, blending = %u",
147                c.fd, c.offset, c.stride,
148                c.x, c.y, c.w, c.h,
149                c.format, c.blending);
150    }
151    else if (c.state == c.S3C_FB_WIN_STATE_COLOR) {
152        ALOGV("\t\tcolor = %u", c.color);
153    }
154}
155
156static void dump_gsc_img(exynos_gsc_img &c)
157{
158    ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u",
159            c.x, c.y, c.w, c.h, c.fw, c.fh);
160    ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u",
161            c.yaddr, c.uaddr, c.vaddr, c.rot, c.cacheable, c.drmMode);
162}
163
164inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
165inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
166template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
167template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
168
169static bool is_transformed(const hwc_layer_1_t &layer)
170{
171    return layer.transform != 0;
172}
173
174static bool is_rotated(const hwc_layer_1_t &layer)
175{
176    return (layer.transform & HAL_TRANSFORM_ROT_90) ||
177            (layer.transform & HAL_TRANSFORM_ROT_180);
178}
179
180static bool is_scaled(const hwc_layer_1_t &layer)
181{
182    return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) ||
183            HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop);
184}
185
186static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format)
187{
188    switch (format) {
189    case HAL_PIXEL_FORMAT_RGBA_8888:
190        return S3C_FB_PIXEL_FORMAT_RGBA_8888;
191    case HAL_PIXEL_FORMAT_RGBX_8888:
192        return S3C_FB_PIXEL_FORMAT_RGBX_8888;
193    case HAL_PIXEL_FORMAT_RGBA_5551:
194        return S3C_FB_PIXEL_FORMAT_RGBA_5551;
195
196    default:
197        return S3C_FB_PIXEL_FORMAT_MAX;
198    }
199}
200
201static bool exynos5_format_is_supported(int format)
202{
203    return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX;
204}
205
206static bool exynos5_format_is_supported_by_gscaler(int format)
207{
208    switch (format) {
209    case HAL_PIXEL_FORMAT_RGBX_8888:
210    case HAL_PIXEL_FORMAT_RGB_565:
211    case HAL_PIXEL_FORMAT_YV12:
212    case HAL_PIXEL_FORMAT_YCbCr_420_P:
213    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
214    case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP:
215    case HAL_PIXEL_FORMAT_YCbCr_420_SP:
216    case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP:
217    case HAL_PIXEL_FORMAT_YCbCr_422_I:
218    case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I:
219    case HAL_PIXEL_FORMAT_YCbCr_422_P:
220    case HAL_PIXEL_FORMAT_CbYCrY_422_I:
221    case HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I:
222    case HAL_PIXEL_FORMAT_YCrCb_422_SP:
223    case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP:
224    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
225    case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP:
226    case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
227    case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED:
228    case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I:
229    case HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I:
230        return true;
231
232    default:
233        return false;
234    }
235}
236
237static bool exynos5_format_is_ycrcb(int format)
238{
239    return format == HAL_PIXEL_FORMAT_YV12;
240}
241
242static bool exynos5_format_requires_gscaler(int format)
243{
244    return exynos5_format_is_supported_by_gscaler(format) &&
245            format != HAL_PIXEL_FORMAT_RGBX_8888;
246}
247
248static uint8_t exynos5_format_to_bpp(int format)
249{
250    switch (format) {
251    case HAL_PIXEL_FORMAT_RGBA_8888:
252    case HAL_PIXEL_FORMAT_RGBX_8888:
253        return 32;
254
255    case HAL_PIXEL_FORMAT_RGBA_5551:
256    case HAL_PIXEL_FORMAT_RGBA_4444:
257        return 16;
258
259    default:
260        ALOGW("unrecognized pixel format %u", format);
261        return 0;
262    }
263}
264
265static bool exynos5_supports_gscaler(hwc_layer_1_t &layer, int format,
266        bool local_path)
267{
268    private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
269
270    int max_w = is_rotated(layer) ? 2048 : 4800;
271    int max_h = is_rotated(layer) ? 2048 : 3344;
272
273    bool rot90or270 = !!(layer.transform & HAL_TRANSFORM_ROT_90);
274    // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 |
275    //                               HAL_TRANSFORM_ROT_180
276
277    int src_w = WIDTH(layer.sourceCrop), src_h = HEIGHT(layer.sourceCrop);
278    int dest_w, dest_h;
279    if (rot90or270) {
280        dest_w = HEIGHT(layer.displayFrame);
281        dest_h = WIDTH(layer.displayFrame);
282    } else {
283        dest_w = WIDTH(layer.displayFrame);
284        dest_h = HEIGHT(layer.displayFrame);
285    }
286    int max_downscale = local_path ? 4 : 16;
287    const int max_upscale = 8;
288
289    return exynos5_format_is_supported_by_gscaler(format) &&
290            handle->stride <= max_w &&
291            handle->stride % GSC_W_ALIGNMENT == 0 &&
292            src_w <= dest_w * max_downscale &&
293            dest_w <= src_w * max_upscale &&
294            handle->height <= max_h &&
295            handle->height % GSC_H_ALIGNMENT == 0 &&
296            src_h <= dest_h * max_downscale &&
297            dest_h <= src_h * max_upscale &&
298            // per 46.2
299            (!rot90or270 || layer.sourceCrop.top % 2 == 0) &&
300            (!rot90or270 || layer.sourceCrop.left % 2 == 0);
301            // per 46.3.1.6
302}
303
304int hdmi_get_config(struct exynos5_hwc_composer_device_1_t *dev)
305{
306    struct v4l2_dv_preset preset;
307    struct v4l2_dv_enum_preset enum_preset;
308    exynos_gsc_img *info = &dev->hdmi_cfg;
309    int index = 0;
310    bool found = false;
311    int ret;
312
313    if (ioctl(dev->hdmi_fd, VIDIOC_G_DV_PRESET, &preset) < 0) {
314        ALOGE("%s: g_dv_preset error, %d", __func__, errno);
315        return -1;
316    }
317
318    while (true) {
319        enum_preset.index = index++;
320        ret = ioctl(dev->hdmi_fd, VIDIOC_ENUM_DV_PRESETS, &enum_preset);
321
322        if (ret < 0) {
323            if (errno == EINVAL)
324                break;
325            ALOGE("%s: enum_dv_presets error, %d", __func__, errno);
326            return -1;
327        }
328
329        ALOGV("%s: %d preset=%02d width=%d height=%d name=%s",
330                __func__, enum_preset.index, enum_preset.preset,
331                enum_preset.width, enum_preset.height, enum_preset.name);
332
333        if (preset.preset == enum_preset.preset) {
334            info->w  = enum_preset.width;
335            info->h  = enum_preset.height;
336            info->fw = enum_preset.width;
337            info->fh = enum_preset.height;
338            info->format = HAL_PIXEL_FORMAT_YV12;
339            found = true;
340        }
341    }
342
343    return found ? 0 : -1;
344}
345
346static enum s3c_fb_blending exynos5_blending_to_s3c_blending(int32_t blending)
347{
348    switch (blending) {
349    case HWC_BLENDING_NONE:
350        return S3C_FB_BLENDING_NONE;
351    case HWC_BLENDING_PREMULT:
352        return S3C_FB_BLENDING_PREMULT;
353    case HWC_BLENDING_COVERAGE:
354        return S3C_FB_BLENDING_COVERAGE;
355
356    default:
357        return S3C_FB_BLENDING_MAX;
358    }
359}
360
361static bool exynos5_blending_is_supported(int32_t blending)
362{
363    return exynos5_blending_to_s3c_blending(blending) < S3C_FB_BLENDING_MAX;
364}
365
366static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev)
367{
368    if (dev->hdmi_mirroring)
369        return 0;
370
371    exynos_gsc_img src_info;
372    int src_w = 2560;
373    int src_h = 1600;
374
375    dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV);
376    if (!dev->hdmi_gsc) {
377        ALOGE("%s: exynos_gsc_create_exclusive failed", __func__);
378        return -ENODEV;
379    }
380
381    memset(&src_info, 0, sizeof(src_info));
382
383    src_info.w = src_w;
384    src_info.h = src_h;
385    src_info.fw = src_w;
386    src_info.fh = src_h;
387    src_info.format = HAL_PIXEL_FORMAT_BGRA_8888;
388
389    int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dev->hdmi_cfg);
390    if (ret < 0) {
391        ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret);
392        exynos_gsc_destroy(dev->hdmi_gsc);
393        dev->hdmi_gsc = NULL;
394        return ret;
395    }
396
397    dev->hdmi_mirroring = true;
398    return 0;
399}
400
401static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev)
402{
403    if (!dev->hdmi_mirroring)
404        return;
405    exynos_gsc_destroy(dev->hdmi_gsc);
406    dev->hdmi_gsc = NULL;
407    dev->hdmi_mirroring = false;
408}
409
410static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb)
411{
412    exynos_gsc_img src_info;
413    exynos_gsc_img dst_info;
414
415    memset(&src_info, 0, sizeof(src_info));
416    memset(&dst_info, 0, sizeof(dst_info));
417
418    src_info.yaddr = fb->fd;
419
420    int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info);
421    if (ret < 0) {
422        ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret);
423        return ret;
424    }
425
426    return 0;
427}
428
429bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i)
430{
431    if (layer.flags & HWC_SKIP_LAYER) {
432        ALOGV("\tlayer %u: skipping", i);
433        return false;
434    }
435
436    private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
437
438    if (!handle) {
439        ALOGV("\tlayer %u: handle is NULL", i);
440        return false;
441    }
442    if (exynos5_format_requires_gscaler(handle->format)) {
443        if (!exynos5_supports_gscaler(layer, handle->format, false)) {
444            ALOGV("\tlayer %u: gscaler required but not supported", i);
445            return false;
446        }
447    } else {
448        if (!exynos5_format_is_supported(handle->format)) {
449            ALOGV("\tlayer %u: pixel format %u not supported", i, handle->format);
450            return false;
451        }
452        if (is_scaled(layer)) {
453            ALOGV("\tlayer %u: scaling not supported", i);
454            return false;
455        }
456        if (is_transformed(layer)) {
457            ALOGV("\tlayer %u: transformations not supported", i);
458            return false;
459        }
460    }
461    if (!exynos5_blending_is_supported(layer.blending)) {
462        ALOGV("\tlayer %u: blending %d not supported", i, layer.blending);
463        return false;
464    }
465
466    return true;
467}
468
469inline bool intersect(const hwc_rect &r1, const hwc_rect &r2)
470{
471    return !(r1.left > r2.right ||
472        r1.right < r2.left ||
473        r1.top > r2.bottom ||
474        r1.bottom < r2.top);
475}
476
477inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2)
478{
479    hwc_rect i;
480    i.top = max(r1.top, r2.top);
481    i.bottom = min(r1.bottom, r2.bottom);
482    i.left = max(r1.left, r2.left);
483    i.right = min(r1.right, r2.right);
484    return i;
485}
486
487static int exynos5_prepare(hwc_composer_device_1_t *dev,
488        size_t numDisplays, hwc_display_contents_1_t** displays)
489{
490    if (!numDisplays || !displays)
491        return 0;
492
493    ALOGV("preparing %u layers", displays[0]->numHwLayers);
494
495    exynos5_hwc_composer_device_1_t *pdev =
496            (exynos5_hwc_composer_device_1_t *)dev;
497    memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays));
498    memset(pdev->bufs.gsc_map, 0, sizeof(pdev->bufs.gsc_map));
499
500    bool force_fb = false;
501    if (pdev->hdmi_hpd) {
502        hdmi_enable(pdev);
503        force_fb = true;
504    } else {
505        hdmi_disable(pdev);
506    }
507
508    for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
509        pdev->bufs.overlay_map[i] = -1;
510
511    bool fb_needed = false;
512    size_t first_fb = 0, last_fb = 0;
513
514    // find unsupported overlays
515    for (size_t i = 0; i < displays[0]->numHwLayers; i++) {
516        hwc_layer_1_t &layer = displays[0]->hwLayers[i];
517
518        if (layer.compositionType == HWC_BACKGROUND && !force_fb) {
519            ALOGV("\tlayer %u: background supported", i);
520            dump_layer(&displays[0]->hwLayers[i]);
521            continue;
522        }
523
524        if (exynos5_supports_overlay(displays[0]->hwLayers[i], i) && !force_fb) {
525            ALOGV("\tlayer %u: overlay supported", i);
526            layer.compositionType = HWC_OVERLAY;
527            dump_layer(&displays[0]->hwLayers[i]);
528            continue;
529        }
530
531        if (!fb_needed) {
532            first_fb = i;
533            fb_needed = true;
534        }
535        last_fb = i;
536        layer.compositionType = HWC_FRAMEBUFFER;
537
538        dump_layer(&displays[0]->hwLayers[i]);
539    }
540
541    // can't composite overlays sandwiched between framebuffers
542    if (fb_needed)
543        for (size_t i = first_fb; i < last_fb; i++)
544            displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
545
546    // Incrementally try to add our supported layers to hardware windows.
547    // If adding a layer would violate a hardware constraint, force it
548    // into the framebuffer and try again.  (Revisiting the entire list is
549    // necessary because adding a layer to the framebuffer can cause other
550    // windows to retroactively violate constraints.)
551    bool changed;
552    do {
553        android::Vector<hwc_rect> rects;
554        android::Vector<hwc_rect> overlaps;
555        size_t pixels_left, windows_left, gsc_left = NUM_GSC_UNITS;
556
557        if (fb_needed) {
558            hwc_rect_t fb_rect;
559            fb_rect.top = fb_rect.left = 0;
560            fb_rect.right = pdev->gralloc_module->xres - 1;
561            fb_rect.bottom = pdev->gralloc_module->yres - 1;
562            pixels_left = MAX_PIXELS - pdev->gralloc_module->xres *
563                    pdev->gralloc_module->yres;
564            windows_left = NUM_HW_WINDOWS - 1;
565            rects.push_back(fb_rect);
566        }
567        else {
568            pixels_left = MAX_PIXELS;
569            windows_left = NUM_HW_WINDOWS;
570        }
571        if (pdev->hdmi_mirroring)
572            gsc_left--;
573
574        changed = false;
575
576        for (size_t i = 0; i < displays[0]->numHwLayers; i++) {
577            hwc_layer_1_t &layer = displays[0]->hwLayers[i];
578            if (layer.flags & HWC_SKIP_LAYER)
579                continue;
580
581            private_handle_t *handle = private_handle_t::dynamicCast(
582                    layer.handle);
583
584            // we've already accounted for the framebuffer above
585            if (layer.compositionType == HWC_FRAMEBUFFER)
586                continue;
587
588            // only layer 0 can be HWC_BACKGROUND, so we can
589            // unconditionally allow it without extra checks
590            if (layer.compositionType == HWC_BACKGROUND) {
591                windows_left--;
592                continue;
593            }
594
595            size_t pixels_needed = WIDTH(layer.displayFrame) *
596                    HEIGHT(layer.displayFrame);
597            bool can_compose = windows_left && pixels_needed <= pixels_left;
598            bool gsc_required = exynos5_format_requires_gscaler(handle->format);
599            if (gsc_required)
600                can_compose = can_compose && gsc_left;
601
602            // hwc_rect_t right and bottom values are normally exclusive;
603            // the intersection logic is simpler if we make them inclusive
604            hwc_rect_t visible_rect = layer.displayFrame;
605            visible_rect.right--; visible_rect.bottom--;
606
607            // no more than 2 layers can overlap on a given pixel
608            for (size_t j = 0; can_compose && j < overlaps.size(); j++) {
609                if (intersect(visible_rect, overlaps.itemAt(j)))
610                    can_compose = false;
611            }
612
613            if (!can_compose) {
614                layer.compositionType = HWC_FRAMEBUFFER;
615                if (!fb_needed) {
616                    first_fb = last_fb = i;
617                    fb_needed = true;
618                }
619                else {
620                    first_fb = min(i, first_fb);
621                    last_fb = max(i, last_fb);
622                }
623                changed = true;
624                break;
625            }
626
627            for (size_t j = 0; j < rects.size(); j++) {
628                const hwc_rect_t &other_rect = rects.itemAt(j);
629                if (intersect(visible_rect, other_rect))
630                    overlaps.push_back(intersection(visible_rect, other_rect));
631            }
632            rects.push_back(visible_rect);
633            pixels_left -= pixels_needed;
634            windows_left--;
635            if (gsc_required)
636                gsc_left--;
637        }
638
639        if (changed)
640            for (size_t i = first_fb; i < last_fb; i++)
641                displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
642    } while(changed);
643
644    unsigned int nextWindow = 0;
645    int nextGsc = 0;
646
647    for (size_t i = 0; i < displays[0]->numHwLayers; i++) {
648        hwc_layer_1_t &layer = displays[0]->hwLayers[i];
649
650        if (fb_needed && i == first_fb) {
651            ALOGV("assigning framebuffer to window %u\n",
652                    nextWindow);
653            nextWindow++;
654            continue;
655        }
656
657        if (layer.compositionType != HWC_FRAMEBUFFER) {
658            ALOGV("assigning layer %u to window %u", i, nextWindow);
659            pdev->bufs.overlay_map[nextWindow] = i;
660            if (layer.compositionType == HWC_OVERLAY) {
661                private_handle_t *handle =
662                        private_handle_t::dynamicCast(layer.handle);
663                if (exynos5_format_requires_gscaler(handle->format)) {
664                    ALOGV("\tusing gscaler %u", nextGsc);
665                    pdev->bufs.gsc_map[i].mode =
666                            exynos5_gsc_map_t::GSC_M2M;
667                    pdev->bufs.gsc_map[i].idx = nextGsc++;
668                }
669            }
670            nextWindow++;
671        }
672    }
673
674    for (size_t i = nextGsc; i < NUM_GSC_UNITS; i++) {
675        for (size_t j = 0; j < NUM_GSC_DST_BUFS; j++)
676            if (pdev->gsc[i].dst_buf[j])
677                pdev->alloc_device->free(pdev->alloc_device,
678                        pdev->gsc[i].dst_buf[j]);
679        memset(&pdev->gsc[i], 0, sizeof(pdev->gsc[i]));
680    }
681
682    if (fb_needed)
683        pdev->bufs.fb_window = first_fb;
684    else
685        pdev->bufs.fb_window = NO_FB_NEEDED;
686
687    return 0;
688}
689
690static inline bool gsc_dst_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2)
691{
692    return c1.x != c2.x ||
693            c1.y != c2.y ||
694            c1.w != c2.w ||
695            c1.h != c2.h ||
696            c1.format != c2.format ||
697            c1.rot != c2.rot ||
698            c1.cacheable != c2.cacheable ||
699            c1.drmMode != c2.drmMode;
700}
701
702static inline bool gsc_src_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2)
703{
704    return gsc_dst_cfg_changed(c1, c2) ||
705            c1.fw != c2.fw ||
706            c1.fh != c2.fh;
707}
708
709static int exynos5_config_gsc_m2m(hwc_layer_1_t &layer,
710        alloc_device_t* alloc_device, exynos5_gsc_data_t *gsc_data,
711        int gsc_idx)
712{
713    ALOGV("configuring gscaler %u for memory-to-memory", gsc_idx);
714
715    private_handle_t *src_handle = private_handle_t::dynamicCast(layer.handle);
716    buffer_handle_t dst_buf;
717    private_handle_t *dst_handle;
718    int ret = 0;
719
720    exynos_gsc_img src_cfg, dst_cfg;
721    memset(&src_cfg, 0, sizeof(src_cfg));
722    memset(&dst_cfg, 0, sizeof(dst_cfg));
723
724    src_cfg.x = layer.sourceCrop.left;
725    src_cfg.y = layer.sourceCrop.top;
726    src_cfg.w = WIDTH(layer.sourceCrop);
727    src_cfg.fw = src_handle->stride;
728    src_cfg.h = HEIGHT(layer.sourceCrop);
729    src_cfg.fh = src_handle->height;
730    src_cfg.yaddr = src_handle->fd;
731    if (exynos5_format_is_ycrcb(src_handle->format)) {
732        src_cfg.uaddr = src_handle->fd2;
733        src_cfg.vaddr = src_handle->fd1;
734    } else {
735        src_cfg.uaddr = src_handle->fd1;
736        src_cfg.vaddr = src_handle->fd2;
737    }
738    src_cfg.format = src_handle->format;
739
740    dst_cfg.x = 0;
741    dst_cfg.y = 0;
742    dst_cfg.w = WIDTH(layer.displayFrame);
743    dst_cfg.h = HEIGHT(layer.displayFrame);
744    dst_cfg.format = HAL_PIXEL_FORMAT_BGRA_8888;
745    dst_cfg.rot = layer.transform;
746
747    ALOGV("source configuration:");
748    dump_gsc_img(src_cfg);
749
750    if (gsc_src_cfg_changed(src_cfg, gsc_data->src_cfg) ||
751            gsc_dst_cfg_changed(dst_cfg, gsc_data->dst_cfg)) {
752        int dst_stride;
753        int usage = GRALLOC_USAGE_SW_READ_NEVER |
754                GRALLOC_USAGE_SW_WRITE_NEVER |
755                GRALLOC_USAGE_HW_COMPOSER;
756        // TODO: add GRALLOC_USAGE_PROTECTED if source buffer is also protected
757
758        int w = ALIGN(WIDTH(layer.displayFrame), GSC_W_ALIGNMENT);
759        int h = ALIGN(HEIGHT(layer.displayFrame), GSC_H_ALIGNMENT);
760
761        for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) {
762            if (gsc_data->dst_buf[i]) {
763                alloc_device->free(alloc_device, gsc_data->dst_buf[i]);
764                gsc_data->dst_buf[i] = NULL;
765            }
766
767            int ret = alloc_device->alloc(alloc_device, w, h,
768                    HAL_PIXEL_FORMAT_RGBX_8888, usage, &gsc_data->dst_buf[i],
769                    &dst_stride);
770            if (ret < 0) {
771                ALOGE("failed to allocate destination buffer: %s",
772                        strerror(-ret));
773                goto err_alloc;
774            }
775        }
776
777        gsc_data->current_buf = 0;
778    }
779
780    dst_buf = gsc_data->dst_buf[gsc_data->current_buf];
781    dst_handle = private_handle_t::dynamicCast(dst_buf);
782
783    dst_cfg.fw = dst_handle->stride;
784    dst_cfg.fh = dst_handle->height;
785    dst_cfg.yaddr = dst_handle->fd;
786
787    ALOGV("destination configuration:");
788    dump_gsc_img(dst_cfg);
789
790    gsc_data->gsc = exynos_gsc_create_exclusive(gsc_idx, GSC_M2M_MODE,
791            GSC_DUMMY);
792    if (!gsc_data->gsc) {
793        ALOGE("failed to create gscaler handle");
794        ret = -1;
795        goto err_alloc;
796    }
797
798    ret = exynos_gsc_config_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg);
799    if (ret < 0) {
800        ALOGE("failed to configure gscaler %u", gsc_idx);
801        goto err_gsc_config;
802    }
803
804    ret = exynos_gsc_run_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg);
805    if (ret < 0) {
806        ALOGE("failed to run gscaler %u", gsc_idx);
807        goto err_gsc_config;
808    }
809
810    gsc_data->src_cfg = src_cfg;
811    gsc_data->dst_cfg = dst_cfg;
812
813    return 0;
814
815err_gsc_config:
816    exynos_gsc_destroy(gsc_data->gsc);
817    gsc_data->gsc = NULL;
818err_alloc:
819    for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) {
820        if (gsc_data->dst_buf[i]) {
821           alloc_device->free(alloc_device, gsc_data->dst_buf[i]);
822           gsc_data->dst_buf[i] = NULL;
823       }
824    }
825    return ret;
826}
827
828static void exynos5_config_handle(private_handle_t *handle,
829        hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame,
830        int32_t blending, s3c_fb_win_config &cfg)
831{
832    cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER;
833    cfg.fd = handle->fd;
834    cfg.x = displayFrame.left;
835    cfg.y = displayFrame.top;
836    cfg.w = WIDTH(displayFrame);
837    cfg.h = HEIGHT(displayFrame);
838    cfg.format = exynos5_format_to_s3c_format(handle->format);
839    uint8_t bpp = exynos5_format_to_bpp(handle->format);
840    cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) * bpp / 8;
841    cfg.stride = handle->stride * bpp / 8;
842    cfg.blending = exynos5_blending_to_s3c_blending(blending);
843}
844
845static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg,
846        const private_module_t *gralloc_module)
847{
848    if (layer->compositionType == HWC_BACKGROUND) {
849        hwc_color_t color = layer->backgroundColor;
850        cfg.state = cfg.S3C_FB_WIN_STATE_COLOR;
851        cfg.color = (color.r << 16) | (color.g << 8) | color.b;
852        cfg.x = 0;
853        cfg.y = 0;
854        cfg.w = gralloc_module->xres;
855        cfg.h = gralloc_module->yres;
856        return;
857    }
858
859    private_handle_t *handle = private_handle_t::dynamicCast(layer->handle);
860    exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame,
861            layer->blending, cfg);
862}
863
864static void exynos5_post_callback(void *data, private_handle_t *fb)
865{
866    exynos5_hwc_post_data_t *pdata = (exynos5_hwc_post_data_t *)data;
867
868    struct s3c_fb_win_config_data win_data;
869    struct s3c_fb_win_config *config = win_data.config;
870    memset(config, 0, sizeof(win_data.config));
871
872    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
873        if ( pdata->overlay_map[i] != -1) {
874            hwc_layer_1_t &layer = pdata->overlays[i];
875            private_handle_t *handle =
876                    private_handle_t::dynamicCast(layer.handle);
877
878            if (layer.acquireFenceFd != -1) {
879                int err = sync_wait(layer.acquireFenceFd, 100);
880                if (err != 0)
881                    ALOGW("fence for layer %zu didn't signal in 100 ms: %s",
882                          i, strerror(errno));
883                close(layer.acquireFenceFd);
884            }
885
886            if (pdata->gsc_map[i].mode == exynos5_gsc_map_t::GSC_M2M) {
887                int gsc_idx = pdata->gsc_map[i].idx;
888                exynos5_config_gsc_m2m(layer, pdata->pdev->alloc_device,
889                        &pdata->pdev->gsc[gsc_idx], gsc_idx);
890            }
891        }
892    }
893
894    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
895        if (i == pdata->fb_window) {
896            hwc_rect_t rect = { 0, 0, fb->width, fb->height };
897            int32_t blending = (i == 0) ? HWC_BLENDING_NONE :
898                    HWC_BLENDING_PREMULT;
899            exynos5_config_handle(fb, rect, rect, blending, config[i]);
900        } else if ( pdata->overlay_map[i] != -1) {
901            hwc_layer_1_t &layer = pdata->overlays[i];
902            private_handle_t *handle =
903                    private_handle_t::dynamicCast(layer.handle);
904
905            if (pdata->gsc_map[i].mode == exynos5_gsc_map_t::GSC_M2M) {
906                int gsc_idx = pdata->gsc_map[i].idx;
907                exynos5_gsc_data_t &gsc = pdata->pdev->gsc[gsc_idx];
908
909                if (!gsc.gsc) {
910                    ALOGE("failed to queue gscaler %u input for layer %u",
911                            gsc_idx, i);
912                    continue;
913                }
914
915                int err = exynos_gsc_stop_exclusive(gsc.gsc);
916                exynos_gsc_destroy(gsc.gsc);
917                gsc.gsc = NULL;
918                if (err < 0) {
919                    ALOGE("failed to dequeue gscaler output for layer %u", i);
920                    continue;
921                }
922
923                buffer_handle_t dst_buf = gsc.dst_buf[gsc.current_buf];
924                gsc.current_buf = (gsc.current_buf + 1) % NUM_GSC_DST_BUFS;
925                private_handle_t *dst_handle =
926                        private_handle_t::dynamicCast(dst_buf);
927                hwc_rect_t sourceCrop = { 0, 0,
928                        WIDTH(layer.displayFrame), HEIGHT(layer.displayFrame) };
929                exynos5_config_handle(dst_handle, sourceCrop,
930                        layer.displayFrame, layer.blending, config[i]);
931            }
932            else {
933                exynos5_config_overlay(&layer, config[i],
934                        pdata->pdev->gralloc_module);
935            }
936        }
937        if (i == 0 && config[i].blending != S3C_FB_BLENDING_NONE) {
938            ALOGV("blending not supported on window 0; forcing BLENDING_NONE");
939            config[i].blending = S3C_FB_BLENDING_NONE;
940        }
941
942        ALOGV("window %u configuration:", i);
943        dump_config(config[i]);
944    }
945
946    int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data);
947    if (ret < 0)
948        ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno);
949
950    if (pdata->pdev->hdmi_mirroring)
951        hdmi_output(pdata->pdev, fb);
952
953    pthread_mutex_lock(&pdata->completion_lock);
954    pdata->fence = win_data.fence;
955    pthread_cond_signal(&pdata->completion);
956    pthread_mutex_unlock(&pdata->completion_lock);
957}
958
959static int exynos5_set(struct hwc_composer_device_1 *dev,
960        size_t numDisplays, hwc_display_contents_1_t** displays)
961{
962    exynos5_hwc_composer_device_1_t *pdev =
963            (exynos5_hwc_composer_device_1_t *)dev;
964
965    if (!numDisplays || !displays || !displays[0] || !displays[0]->dpy || !displays[0]->sur)
966        return 0;
967
968    hwc_callback_queue_t *queue = NULL;
969    pthread_mutex_t *lock = NULL;
970    exynos5_hwc_post_data_t *data = NULL;
971
972    if (displays[0]->numHwLayers) {
973        for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
974            if (pdev->bufs.overlay_map[i] != -1) {
975                pdev->bufs.overlays[i] =
976                    displays[0]->hwLayers[pdev->bufs.overlay_map[i]];
977            }
978        }
979
980        data = (exynos5_hwc_post_data_t *)
981                malloc(sizeof(exynos5_hwc_post_data_t));
982        memcpy(data, &pdev->bufs, sizeof(pdev->bufs));
983
984        data->fence = -1;
985        pthread_mutex_init(&data->completion_lock, NULL);
986        pthread_cond_init(&data->completion, NULL);
987
988        if (pdev->bufs.fb_window == NO_FB_NEEDED) {
989            exynos5_post_callback(data, NULL);
990        } else {
991
992            struct hwc_callback_entry entry;
993            entry.callback = exynos5_post_callback;
994            entry.data = data;
995
996            queue = reinterpret_cast<hwc_callback_queue_t *>(
997                pdev->gralloc_module->queue);
998            lock = const_cast<pthread_mutex_t *>(
999                &pdev->gralloc_module->queue_lock);
1000
1001            pthread_mutex_lock(lock);
1002            queue->push_front(entry);
1003            pthread_mutex_unlock(lock);
1004
1005            EGLBoolean success = eglSwapBuffers((EGLDisplay)displays[0]->dpy,
1006                    (EGLSurface)displays[0]->sur);
1007            if (!success) {
1008                ALOGE("HWC_EGL_ERROR");
1009                if (displays[0]) {
1010                    pthread_mutex_lock(lock);
1011                    queue->removeAt(0);
1012                    pthread_mutex_unlock(lock);
1013                    free(data);
1014                }
1015                return HWC_EGL_ERROR;
1016            }
1017        }
1018    }
1019
1020
1021    pthread_mutex_lock(&data->completion_lock);
1022    while (data->fence == -1)
1023        pthread_cond_wait(&data->completion, &data->completion_lock);
1024    pthread_mutex_unlock(&data->completion_lock);
1025
1026    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
1027        if (pdev->bufs.overlay_map[i] != -1) {
1028            int dup_fd = dup(data->fence);
1029            if (dup_fd < 0)
1030                ALOGW("release fence dup failed: %s", strerror(errno));
1031            displays[0]->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd;
1032        }
1033    }
1034    close(data->fence);
1035    free(data);
1036    return 0;
1037}
1038
1039static void exynos5_registerProcs(struct hwc_composer_device_1* dev,
1040        hwc_procs_t const* procs)
1041{
1042    struct exynos5_hwc_composer_device_1_t* pdev =
1043            (struct exynos5_hwc_composer_device_1_t*)dev;
1044    pdev->procs = const_cast<hwc_procs_t *>(procs);
1045}
1046
1047static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
1048{
1049    struct exynos5_hwc_composer_device_1_t *pdev =
1050            (struct exynos5_hwc_composer_device_1_t *)dev;
1051
1052    switch (what) {
1053    case HWC_BACKGROUND_LAYER_SUPPORTED:
1054        // we support the background layer
1055        value[0] = 1;
1056        break;
1057    case HWC_VSYNC_PERIOD:
1058        // vsync period in nanosecond
1059        value[0] = 1000000000.0 / pdev->gralloc_module->fps;
1060        break;
1061    default:
1062        // unsupported query
1063        return -EINVAL;
1064    }
1065    return 0;
1066}
1067
1068static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int dpy,
1069        int event, int enabled)
1070{
1071    struct exynos5_hwc_composer_device_1_t *pdev =
1072            (struct exynos5_hwc_composer_device_1_t *)dev;
1073
1074    switch (event) {
1075    case HWC_EVENT_VSYNC:
1076        __u32 val = !!enabled;
1077        int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val);
1078        if (err < 0) {
1079            ALOGE("vsync ioctl failed");
1080            return -errno;
1081        }
1082
1083        return 0;
1084    }
1085
1086    return -EINVAL;
1087}
1088
1089static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
1090        const char *buff, int len)
1091{
1092    const char *s = buff;
1093    s += strlen(s) + 1;
1094
1095    while (*s) {
1096        if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
1097            pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
1098
1099        s += strlen(s) + 1;
1100        if (s - buff >= len)
1101            break;
1102    }
1103
1104    if (pdev->hdmi_hpd) {
1105        if (hdmi_get_config(pdev)) {
1106            ALOGE("Error reading HDMI configuration");
1107            pdev->hdmi_hpd = false;
1108            return;
1109        }
1110    }
1111
1112    ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
1113    if (pdev->hdmi_hpd)
1114        ALOGI("HDMI Resolution changed to %dx%d", pdev->hdmi_cfg.h, pdev->hdmi_cfg.w);
1115
1116    if (pdev->procs && pdev->procs->invalidate)
1117        pdev->procs->invalidate(pdev->procs);
1118}
1119
1120static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev)
1121{
1122    if (!pdev->procs || !pdev->procs->vsync)
1123        return;
1124
1125    int err = lseek(pdev->vsync_fd, 0, SEEK_SET);
1126    if (err < 0) {
1127        ALOGE("error seeking to vsync timestamp: %s", strerror(errno));
1128        return;
1129    }
1130
1131    char buf[4096];
1132    err = read(pdev->vsync_fd, buf, sizeof(buf));
1133    if (err < 0) {
1134        ALOGE("error reading vsync timestamp: %s", strerror(errno));
1135        return;
1136    }
1137    buf[sizeof(buf) - 1] = '\0';
1138
1139    errno = 0;
1140    uint64_t timestamp = strtoull(buf, NULL, 0);
1141    if (!errno)
1142        pdev->procs->vsync(pdev->procs, 0, timestamp);
1143}
1144
1145static void *hwc_vsync_thread(void *data)
1146{
1147    struct exynos5_hwc_composer_device_1_t *pdev =
1148            (struct exynos5_hwc_composer_device_1_t *)data;
1149    char uevent_desc[4096];
1150    memset(uevent_desc, 0, sizeof(uevent_desc));
1151
1152    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
1153
1154    uevent_init();
1155
1156    char temp[4096];
1157    int err = read(pdev->vsync_fd, temp, sizeof(temp));
1158    if (err < 0) {
1159        ALOGE("error reading vsync timestamp: %s", strerror(errno));
1160        return NULL;
1161    }
1162
1163    struct pollfd fds[2];
1164    fds[0].fd = pdev->vsync_fd;
1165    fds[0].events = POLLPRI;
1166    fds[1].fd = uevent_get_fd();
1167    fds[1].events = POLLIN;
1168
1169    while (true) {
1170        int err = poll(fds, 2, -1);
1171
1172        if (err > 0) {
1173            if (fds[0].revents & POLLPRI) {
1174                handle_vsync_event(pdev);
1175            }
1176            else if (fds[1].revents & POLLIN) {
1177                int len = uevent_next_event(uevent_desc,
1178                        sizeof(uevent_desc) - 2);
1179
1180                bool hdmi = !strcmp(uevent_desc,
1181                        "change@/devices/virtual/switch/hdmi");
1182                if (hdmi)
1183                    handle_hdmi_uevent(pdev, uevent_desc, len);
1184            }
1185        }
1186        else if (err == -1) {
1187            if (errno == EINTR)
1188                break;
1189            ALOGE("error in vsync thread: %s", strerror(errno));
1190        }
1191    }
1192
1193    return NULL;
1194}
1195
1196static int exynos5_blank(struct hwc_composer_device_1 *dev, int dpy, int blank)
1197{
1198    struct exynos5_hwc_composer_device_1_t *pdev =
1199            (struct exynos5_hwc_composer_device_1_t *)dev;
1200
1201    int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
1202    int err = ioctl(pdev->fd, FBIOBLANK, fb_blank);
1203    if (err < 0) {
1204        ALOGE("%sblank ioctl failed", blank ? "" : "un");
1205        return -errno;
1206    }
1207
1208    return 0;
1209}
1210
1211struct hwc_methods_1 exynos5_methods = {
1212    eventControl: exynos5_eventControl,
1213    blank: exynos5_blank,
1214};
1215
1216static int exynos5_close(hw_device_t* device);
1217
1218static int exynos5_open(const struct hw_module_t *module, const char *name,
1219        struct hw_device_t **device)
1220{
1221    int ret;
1222    int sw_fd;
1223
1224    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1225        return -EINVAL;
1226    }
1227
1228    struct exynos5_hwc_composer_device_1_t *dev;
1229    dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev));
1230    memset(dev, 0, sizeof(*dev));
1231
1232    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
1233            (const struct hw_module_t **)&dev->gralloc_module)) {
1234        ALOGE("failed to get gralloc hw module");
1235        ret = -EINVAL;
1236        goto err_get_module;
1237    }
1238
1239    if (gralloc_open((const hw_module_t *)dev->gralloc_module,
1240            &dev->alloc_device)) {
1241        ALOGE("failed to open gralloc");
1242        ret = -EINVAL;
1243        goto err_get_module;
1244    }
1245
1246    dev->fd = open("/dev/graphics/fb0", O_RDWR);
1247    if (dev->fd < 0) {
1248        ALOGE("failed to open framebuffer");
1249        ret = dev->fd;
1250        goto err_open_fb;
1251    }
1252
1253    dev->hdmi_fd = open("/dev/video16", O_RDWR);
1254    if (dev->hdmi_fd < 0) {
1255        ALOGE("failed to open hdmi device");
1256        ret = dev->hdmi_fd;
1257        goto err_ioctl;
1258    }
1259
1260    dev->vsync_fd = open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY);
1261    if (dev->vsync_fd < 0) {
1262        ALOGE("failed to open vsync attribute");
1263        ret = dev->vsync_fd;
1264        goto err_hdmi;
1265    }
1266
1267    sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
1268    if (sw_fd) {
1269        char val;
1270        if (read(sw_fd, &val, 1) == 1 && val == '1')
1271            dev->hdmi_hpd = true;
1272    }
1273
1274    dev->base.common.tag = HARDWARE_DEVICE_TAG;
1275    dev->base.common.version = HWC_DEVICE_API_VERSION_1_0;
1276    dev->base.common.module = const_cast<hw_module_t *>(module);
1277    dev->base.common.close = exynos5_close;
1278
1279    dev->base.prepare = exynos5_prepare;
1280    dev->base.set = exynos5_set;
1281    dev->base.registerProcs = exynos5_registerProcs;
1282    dev->base.query = exynos5_query;
1283    dev->base.methods = &exynos5_methods;
1284
1285    dev->bufs.pdev = dev;
1286
1287    *device = &dev->base.common;
1288
1289    ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
1290    if (ret) {
1291        ALOGE("failed to start vsync thread: %s", strerror(ret));
1292        ret = -ret;
1293        goto err_vsync;
1294    }
1295
1296    return 0;
1297
1298err_vsync:
1299    close(dev->vsync_fd);
1300err_hdmi:
1301    close(dev->hdmi_fd);
1302err_ioctl:
1303    close(dev->fd);
1304err_open_fb:
1305    gralloc_close(dev->alloc_device);
1306err_get_module:
1307    free(dev);
1308    return ret;
1309}
1310
1311static int exynos5_close(hw_device_t *device)
1312{
1313    struct exynos5_hwc_composer_device_1_t *dev =
1314            (struct exynos5_hwc_composer_device_1_t *)device;
1315    pthread_kill(dev->vsync_thread, SIGTERM);
1316    pthread_join(dev->vsync_thread, NULL);
1317    for (size_t i = 0; i < NUM_GSC_UNITS; i++) {
1318        if (dev->gsc[i].gsc)
1319            exynos_gsc_destroy(dev->gsc[i].gsc);
1320        for (size_t j = 0; i < NUM_GSC_DST_BUFS; j++)
1321            if (dev->gsc[i].dst_buf[j])
1322                dev->alloc_device->free(dev->alloc_device, dev->gsc[i].dst_buf[j]);
1323    }
1324    gralloc_close(dev->alloc_device);
1325    close(dev->vsync_fd);
1326    close(dev->hdmi_fd);
1327    close(dev->fd);
1328    return 0;
1329}
1330
1331static struct hw_module_methods_t exynos5_hwc_module_methods = {
1332    open: exynos5_open,
1333};
1334
1335hwc_module_t HAL_MODULE_INFO_SYM = {
1336    common: {
1337        tag: HARDWARE_MODULE_TAG,
1338        module_api_version: HWC_MODULE_API_VERSION_0_1,
1339        hal_api_version: HARDWARE_HAL_API_VERSION,
1340        id: HWC_HARDWARE_MODULE_ID,
1341        name: "Samsung exynos5 hwcomposer module",
1342        author: "Google",
1343        methods: &exynos5_hwc_module_methods,
1344    }
1345};
1346