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