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