hardware/intel/hwcomposer
Revision | cd1bb931979e5a0b9b8f267fa2347bd8d9c28a1b (tree) |
---|---|
Zeit | 2013-05-16 21:19:44 |
Autor | Marius Predut <marius-ionut.predut@inte...> |
Commiter | Marius Predut |
Added support in the hwc to provide refresh timestamps to the surface flinger.
It is done using the same fake mechanism as SF uses. This is prefered until the refresh time stamps will be provides.
v4 (topi):
v5 (topi/tapani):
v6(topi/tapani):
Reviewed-by: Topi Pohjolainen <topi.pohjolainen@intel.com>
Change-Id: I927e62b5c8c53db859bd194b75f1b92028ea0d85
Signed-off-by: Marius Predut <marius-ionut.predut@intel.com>
@@ -17,9 +17,9 @@ LOCAL_PATH := $(call my-dir) | ||
17 | 17 | include $(CLEAR_VARS) |
18 | 18 | |
19 | 19 | LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw |
20 | -LOCAL_SHARED_LIBRARIES := liblog libEGL libhardware | |
20 | +LOCAL_SHARED_LIBRARIES := liblog libEGL libhardware libutils libdrm | |
21 | 21 | LOCAL_CFLAGS := -DEGL_EGLEXT_PROTOTYPES |
22 | -LOCAL_C_INCLUDES += bionic hardware/drm_gralloc external/drm external/drm/include/drm | |
22 | +LOCAL_C_INCLUDES += frameworks/native/include/utils/ hardware/drm_gralloc external/drm external/drm/include/drm | |
23 | 23 | LOCAL_SRC_FILES := hwcomposer.cpp |
24 | 24 | LOCAL_MODULE := hwcomposer.$(TARGET_PRODUCT) |
25 | 25 | LOCAL_MODULE_TAGS := optional |
@@ -34,10 +34,12 @@ | ||
34 | 34 | |
35 | 35 | #define HWC_REMOVE_DEPRECATED_VERSIONS 1 |
36 | 36 | |
37 | -struct hwc_context_t { | |
38 | - hwc_composer_device_1 device; | |
39 | - struct drm_module_t *gralloc_module; | |
40 | -}; | |
37 | +#include <Condition.h> | |
38 | +#include <Mutex.h> | |
39 | +#include <Thread.h> | |
40 | +#include <StrongPointer.h> | |
41 | + | |
42 | +#define SEC_TO_NANOSEC (1000 * 1000 * 1000) | |
41 | 43 | |
42 | 44 | static int hwc_device_open(const struct hw_module_t* module, const char* name, |
43 | 45 | struct hw_device_t** device); |
@@ -59,6 +61,62 @@ hwc_module_t HAL_MODULE_INFO_SYM = { | ||
59 | 61 | }; |
60 | 62 | |
61 | 63 | |
64 | +/** | |
65 | +* Fake VSync class. | |
66 | +* To provide refresh timestamps to the surface flinger, using the | |
67 | +* same fake mechanism as SF uses on its own, and this is because one | |
68 | +* cannot start using hwc until it provides certain mandatory things - the | |
69 | +* refresh time stamps being one of them. | |
70 | +*/ | |
71 | +class vsync_worker : public android::Thread { | |
72 | +public: | |
73 | + vsync_worker(struct hwc_context_t& hwc); | |
74 | + void set_enabled(bool enabled); | |
75 | +private: | |
76 | + virtual void onFirstRef(); | |
77 | + virtual bool threadLoop(); | |
78 | + void wait_until_enabled(); | |
79 | +private: | |
80 | + struct hwc_context_t& dev; | |
81 | + mutable android::Mutex lock; | |
82 | + android::Condition condition; | |
83 | + bool enabled; | |
84 | + mutable int64_t next_fake_vsync; | |
85 | + int64_t refresh_period; | |
86 | +}; | |
87 | + | |
88 | +struct hwc_context_t { | |
89 | + hwc_composer_device_1 device; | |
90 | + struct drm_module_t *gralloc_module; | |
91 | + hwc_procs_t *procs; | |
92 | + android::sp<vsync_worker> vsync_thread; | |
93 | +}; | |
94 | + | |
95 | +static void hwc_register_procs(hwc_composer_device_1 *dev, | |
96 | + hwc_procs_t const* procs) | |
97 | +{ | |
98 | + struct hwc_context_t* ctx = (struct hwc_context_t*)dev; | |
99 | + ctx->procs = (hwc_procs_t *) procs; | |
100 | +} | |
101 | + | |
102 | +static int hwc_event_control(hwc_composer_device_1 *dev, int disp, int event, | |
103 | + int enabled) | |
104 | +{ | |
105 | + hwc_context_t* ctx = (hwc_context_t*)dev; | |
106 | + | |
107 | + /** | |
108 | + * The API restricts 'enabled' as having boolean values only. Also for | |
109 | + * now there can be only one fixed display having identifier zero. | |
110 | + */ | |
111 | + if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1) || disp) | |
112 | + return -EINVAL; | |
113 | + | |
114 | + if (ctx->vsync_thread != NULL) | |
115 | + ctx->vsync_thread->set_enabled(enabled); | |
116 | + | |
117 | + return 0; | |
118 | +} | |
119 | + | |
62 | 120 | static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, |
63 | 121 | hwc_display_contents_1_t** displays) |
64 | 122 | { |
@@ -161,6 +219,9 @@ static int hwc_device_close(struct hw_device_t *dev) | ||
161 | 219 | if (ctx) |
162 | 220 | free(ctx); |
163 | 221 | |
222 | + if (ctx->vsync_thread != NULL) | |
223 | + ctx->vsync_thread->requestExitAndWait(); | |
224 | + | |
164 | 225 | return 0; |
165 | 226 | } |
166 | 227 |
@@ -178,7 +239,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, | ||
178 | 239 | |
179 | 240 | /* initialize the procs */ |
180 | 241 | dev->device.common.tag = HARDWARE_DEVICE_TAG; |
181 | - dev->device.common.version = 0; | |
242 | + dev->device.common.version = HWC_DEVICE_API_VERSION_1_0; | |
182 | 243 | dev->device.common.module = const_cast<hw_module_t*>(module); |
183 | 244 | dev->device.common.close = hwc_device_close; |
184 | 245 |
@@ -187,13 +248,105 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, | ||
187 | 248 | dev->device.blank = hwc_blank; |
188 | 249 | dev->device.getDisplayAttributes = hwc_get_display_attrs; |
189 | 250 | dev->device.getDisplayConfigs = hwc_get_display_cfgs; |
251 | + dev->device.registerProcs = hwc_register_procs; | |
252 | + dev->device.eventControl = hwc_event_control; | |
190 | 253 | |
191 | 254 | *device = &dev->device.common; |
192 | 255 | |
193 | 256 | int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, |
194 | 257 | (const hw_module_t **)&dev->gralloc_module); |
195 | 258 | |
259 | + dev->vsync_thread = new vsync_worker(*dev); | |
260 | + | |
196 | 261 | ALOGD("Intel hwcomposer module"); |
197 | 262 | |
198 | 263 | return 0; |
199 | 264 | } |
265 | + | |
266 | +/* This is needed here as bionic itself is missing the prototype */ | |
267 | +extern "C" int clock_nanosleep(clockid_t clock_id, int flags, | |
268 | + const struct timespec *request, struct timespec *remain); | |
269 | + | |
270 | +/** | |
271 | + * XXX: this code is temporary and comes from SurfaceFlinger.cpp | |
272 | + * so I changed as little as possible since the code will be dropped | |
273 | + * anyway, when real functionality will be implemented | |
274 | + */ | |
275 | +vsync_worker::vsync_worker(struct hwc_context_t& mydev) | |
276 | + : dev(mydev), enabled(false), next_fake_vsync(0) | |
277 | +{ | |
278 | + int64_t refresh = 0; | |
279 | + framebuffer_device_t* fbdev; | |
280 | + | |
281 | + int err = framebuffer_open((const hw_module_t *)dev.gralloc_module, &fbdev); | |
282 | + if (err) | |
283 | + ALOGE("framebuffer_open failed (%s)", strerror(-err)); | |
284 | + else | |
285 | + refresh = int64_t(SEC_TO_NANOSEC / fbdev->fps); | |
286 | + | |
287 | + if (refresh == 0) { | |
288 | + refresh = int64_t(SEC_TO_NANOSEC / 60.0); | |
289 | + ALOGW("getting VSYNC period from thin air: %lld", refresh); | |
290 | + } else | |
291 | + ALOGW("getting VSYNC period from fb HAL: %lld", refresh); | |
292 | + | |
293 | + refresh_period = refresh; | |
294 | +} | |
295 | + | |
296 | +void vsync_worker::set_enabled(bool _enabled) | |
297 | +{ | |
298 | + android::Mutex::Autolock _l(lock); | |
299 | + if (enabled != _enabled) { | |
300 | + enabled = _enabled; | |
301 | + condition.signal(); | |
302 | + } | |
303 | +} | |
304 | + | |
305 | +void vsync_worker::wait_until_enabled() | |
306 | +{ | |
307 | + android::Mutex::Autolock _l(lock); | |
308 | + | |
309 | + while (!enabled) { | |
310 | + condition.wait(lock); | |
311 | + } | |
312 | +} | |
313 | + | |
314 | +void vsync_worker::onFirstRef() | |
315 | +{ | |
316 | + run("vsync_thread", android::PRIORITY_URGENT_DISPLAY + | |
317 | + android::PRIORITY_MORE_FAVORABLE); | |
318 | +} | |
319 | + | |
320 | +bool vsync_worker::threadLoop() | |
321 | +{ | |
322 | + wait_until_enabled(); | |
323 | + | |
324 | + const int64_t now = systemTime(CLOCK_MONOTONIC); | |
325 | + int64_t next_vsync = next_fake_vsync; | |
326 | + int64_t sleep = next_vsync - now; | |
327 | + if (sleep < 0) { | |
328 | + /* we missed, find where the next vsync should be */ | |
329 | + ALOGV("vsync missed!"); | |
330 | + sleep = (refresh_period - ((now - next_vsync) % refresh_period)); | |
331 | + next_vsync = now + sleep; | |
332 | + } | |
333 | + | |
334 | + next_fake_vsync = next_vsync + refresh_period; | |
335 | + | |
336 | + struct timespec spec; | |
337 | + spec.tv_sec = next_vsync / SEC_TO_NANOSEC; | |
338 | + spec.tv_nsec = next_vsync % SEC_TO_NANOSEC; | |
339 | + | |
340 | + int err; | |
341 | + do { | |
342 | + err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); | |
343 | + } while (err < 0 && errno == EINTR); | |
344 | + | |
345 | + if (err == 0) | |
346 | + dev.procs->vsync(dev.procs, 0, next_vsync); | |
347 | + else | |
348 | + ALOGE("clock_nanosleep failed with error %d ", err); | |
349 | + | |
350 | + return true; | |
351 | +} | |
352 | + |