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 <pthread.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <sys/resource.h>
22#include <unistd.h>
23
24#include <log/log.h>
25#include <hardware/hwcomposer.h>
26#include <sync/sync.h>
27
28struct ranchu_hwc_composer_device_1 {
29    hwc_composer_device_1_t base; // constant after init
30    const hwc_procs_t *procs;     // constant after init
31    pthread_t vsync_thread;       // constant after init
32    int32_t vsync_period_ns;      // constant after init
33    framebuffer_device_t* fbdev;  // constant after init
34
35    pthread_mutex_t vsync_lock;
36    bool vsync_callback_enabled; // protected by this->vsync_lock
37};
38
39static int hwc_prepare(hwc_composer_device_1_t* dev __unused,
40                       size_t numDisplays, hwc_display_contents_1_t** displays) {
41
42    if (!numDisplays || !displays) return 0;
43
44    hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
45
46    if (!contents) return 0;
47
48    for (size_t i = 0; i < contents->numHwLayers; i++) {
49    // We do not handle any layers, so set composition type of any non
50    // HWC_FRAMEBUFFER_TARGET layer to to HWC_FRAMEBUFFER.
51        if (contents->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
52            continue;
53        }
54        contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
55    }
56    return 0;
57}
58
59static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays,
60                   hwc_display_contents_1_t** displays) {
61    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
62    if (!numDisplays || !displays) {
63        return 0;
64    }
65
66    hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
67
68    int retireFenceFd = -1;
69    int err = 0;
70    for (size_t layer = 0; layer < contents->numHwLayers; layer++) {
71            hwc_layer_1_t* fb_layer = &contents->hwLayers[layer];
72
73        int releaseFenceFd = -1;
74        if (fb_layer->acquireFenceFd > 0) {
75            const int kAcquireWarningMS= 3000;
76            err = sync_wait(fb_layer->acquireFenceFd, kAcquireWarningMS);
77            if (err < 0 && errno == ETIME) {
78                ALOGE("hwcomposer waited on fence %d for %d ms",
79                      fb_layer->acquireFenceFd, kAcquireWarningMS);
80            }
81            close(fb_layer->acquireFenceFd);
82
83            if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
84                ALOGE("hwcomposer found acquire fence on layer %d which is not an"
85                      "HWC_FRAMEBUFFER_TARGET layer", layer);
86            }
87
88            releaseFenceFd = dup(fb_layer->acquireFenceFd);
89            fb_layer->acquireFenceFd = -1;
90        }
91
92        if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
93            continue;
94        }
95
96        pdev->fbdev->post(pdev->fbdev, fb_layer->handle);
97        fb_layer->releaseFenceFd = releaseFenceFd;
98
99        if (releaseFenceFd > 0) {
100            if (retireFenceFd == -1) {
101                retireFenceFd = dup(releaseFenceFd);
102            } else {
103                int mergedFenceFd = sync_merge("hwc_set retireFence",
104                                               releaseFenceFd, retireFenceFd);
105                close(retireFenceFd);
106                retireFenceFd = mergedFenceFd;
107            }
108        }
109    }
110
111    contents->retireFenceFd = retireFenceFd;
112    return err;
113}
114
115static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) {
116    struct ranchu_hwc_composer_device_1* pdev =
117            (struct ranchu_hwc_composer_device_1*)dev;
118
119    switch (what) {
120        case HWC_BACKGROUND_LAYER_SUPPORTED:
121            // we do not support the background layer
122            value[0] = 0;
123            break;
124        case HWC_VSYNC_PERIOD:
125            value[0] = pdev->vsync_period_ns;
126            break;
127        default:
128            // unsupported query
129            ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
130            return -EINVAL;
131    }
132    return 0;
133}
134
135static int hwc_event_control(struct hwc_composer_device_1* dev, int dpy __unused,
136                             int event, int enabled) {
137    struct ranchu_hwc_composer_device_1* pdev =
138            (struct ranchu_hwc_composer_device_1*)dev;
139    int ret = -EINVAL;
140
141    // enabled can only be 0 or 1
142    if (!(enabled & ~1)) {
143        if (event == HWC_EVENT_VSYNC) {
144            pthread_mutex_lock(&pdev->vsync_lock);
145            pdev->vsync_callback_enabled=enabled;
146            pthread_mutex_unlock(&pdev->vsync_lock);
147            ret = 0;
148        }
149    }
150    return ret;
151}
152
153static int hwc_blank(struct hwc_composer_device_1* dev __unused, int disp,
154                     int blank __unused) {
155    if (disp != HWC_DISPLAY_PRIMARY) {
156        return -EINVAL;
157    }
158    return 0;
159}
160
161static void hwc_dump(hwc_composer_device_1* dev __unused, char* buff __unused,
162                     int buff_len __unused) {
163    // This is run when running dumpsys.
164    // No-op for now.
165}
166
167
168static int hwc_get_display_configs(struct hwc_composer_device_1* dev __unused,
169                                   int disp, uint32_t* configs, size_t* numConfigs) {
170    if (*numConfigs == 0) {
171        return 0;
172    }
173
174    if (disp == HWC_DISPLAY_PRIMARY) {
175        configs[0] = 0;
176        *numConfigs = 1;
177        return 0;
178    }
179
180    return -EINVAL;
181}
182
183
184static int32_t hwc_attribute(struct ranchu_hwc_composer_device_1* pdev,
185                             const uint32_t attribute) {
186    switch(attribute) {
187        case HWC_DISPLAY_VSYNC_PERIOD:
188            return pdev->vsync_period_ns;
189        case HWC_DISPLAY_WIDTH:
190            return pdev->fbdev->width;
191        case HWC_DISPLAY_HEIGHT:
192            return pdev->fbdev->height;
193        case HWC_DISPLAY_DPI_X:
194            return pdev->fbdev->xdpi*1000;
195        case HWC_DISPLAY_DPI_Y:
196            return pdev->fbdev->ydpi*1000;
197        default:
198            ALOGE("unknown display attribute %u", attribute);
199            return -EINVAL;
200    }
201}
202
203static int hwc_get_display_attributes(struct hwc_composer_device_1* dev __unused,
204                                      int disp, uint32_t config __unused,
205                                      const uint32_t* attributes, int32_t* values) {
206
207    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
208    for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
209        if (disp == HWC_DISPLAY_PRIMARY) {
210            values[i] = hwc_attribute(pdev, attributes[i]);
211            if (values[i] == -EINVAL) {
212                return -EINVAL;
213            }
214        } else {
215            ALOGE("unknown display type %u", disp);
216            return -EINVAL;
217        }
218    }
219
220    return 0;
221}
222
223static int hwc_close(hw_device_t* dev) {
224    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
225    pthread_kill(pdev->vsync_thread, SIGTERM);
226    pthread_join(pdev->vsync_thread, NULL);
227    free(dev);
228    return 0;
229}
230
231static void* hwc_vsync_thread(void* data) {
232    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)data;
233    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
234
235    struct timespec rt;
236    if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
237        ALOGE("%s:%d error in vsync thread clock_gettime: %s",
238              __FILE__, __LINE__, strerror(errno));
239    }
240    const int log_interval = 60;
241    int64_t last_logged = rt.tv_sec;
242    int sent = 0;
243    int last_sent = 0;
244    bool vsync_enabled = false;
245    struct timespec wait_time;
246    wait_time.tv_sec = 0;
247    wait_time.tv_nsec = pdev->vsync_period_ns;
248
249    while (true) {
250        int err = nanosleep(&wait_time, NULL);
251        if (err == -1) {
252            if (errno == EINTR) {
253                break;
254            }
255            ALOGE("error in vsync thread: %s", strerror(errno));
256        }
257
258        pthread_mutex_lock(&pdev->vsync_lock);
259        vsync_enabled = pdev->vsync_callback_enabled;
260        pthread_mutex_unlock(&pdev->vsync_lock);
261
262        if (!vsync_enabled) {
263            continue;
264        }
265
266        if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
267            ALOGE("%s:%d error in vsync thread clock_gettime: %s",
268                  __FILE__, __LINE__, strerror(errno));
269        }
270
271        int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
272        pdev->procs->vsync(pdev->procs, 0, timestamp);
273        if (rt.tv_sec - last_logged >= log_interval) {
274            ALOGD("hw_composer sent %d syncs in %ds", sent - last_sent, rt.tv_sec - last_logged);
275            last_logged = rt.tv_sec;
276            last_sent = sent;
277        }
278        ++sent;
279    }
280
281    return NULL;
282}
283
284static void hwc_register_procs(struct hwc_composer_device_1* dev,
285                               hwc_procs_t const* procs) {
286    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
287    pdev->procs = procs;
288}
289
290static int hwc_open(const struct hw_module_t* module, const char* name,
291                    struct hw_device_t** device) {
292    int ret = 0;
293
294    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
295        ALOGE("%s called with bad name %s", __FUNCTION__, name);
296        return -EINVAL;
297    }
298
299    ranchu_hwc_composer_device_1 *pdev = new ranchu_hwc_composer_device_1();
300    if (!pdev) {
301        ALOGE("%s failed to allocate dev", __FUNCTION__);
302        return -ENOMEM;
303    }
304
305    pdev->base.common.tag = HARDWARE_DEVICE_TAG;
306    pdev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
307    pdev->base.common.module = const_cast<hw_module_t *>(module);
308    pdev->base.common.close = hwc_close;
309
310    pdev->base.prepare = hwc_prepare;
311    pdev->base.set = hwc_set;
312    pdev->base.eventControl = hwc_event_control;
313    pdev->base.blank = hwc_blank;
314    pdev->base.query = hwc_query;
315    pdev->base.registerProcs = hwc_register_procs;
316    pdev->base.dump = hwc_dump;
317    pdev->base.getDisplayConfigs = hwc_get_display_configs;
318    pdev->base.getDisplayAttributes = hwc_get_display_attributes;
319
320    pdev->vsync_period_ns = 1000*1000*1000/60; // vsync is 60 hz
321
322    hw_module_t const* hw_module;
323    ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module);
324    if (ret != 0) {
325        ALOGE("ranchu_hw_composer hwc_open %s module not found", GRALLOC_HARDWARE_MODULE_ID);
326        return ret;
327    }
328    ret = framebuffer_open(hw_module, &pdev->fbdev);
329    if (ret != 0) {
330        ALOGE("ranchu_hw_composer hwc_open could not open framebuffer");
331    }
332
333    pthread_mutex_init(&pdev->vsync_lock, NULL);
334    pdev->vsync_callback_enabled = false;
335
336    ret = pthread_create (&pdev->vsync_thread, NULL, hwc_vsync_thread, pdev);
337    if (ret) {
338        ALOGE("ranchu_hw_composer could not start vsync_thread\n");
339    }
340
341    *device = &pdev->base.common;
342
343    return ret;
344}
345
346
347static struct hw_module_methods_t hwc_module_methods = {
348    open: hwc_open,
349};
350
351hwc_module_t HAL_MODULE_INFO_SYM = {
352    common: {
353        tag: HARDWARE_MODULE_TAG,
354        module_api_version: HWC_MODULE_API_VERSION_0_1,
355        hal_api_version: HARDWARE_HAL_API_VERSION,
356        id: HWC_HARDWARE_MODULE_ID,
357        name: "Android Emulator hwcomposer module",
358        author: "The Android Open Source Project",
359        methods: &hwc_module_methods,
360    }
361};
362