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