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