OSDN Git Service

Added support in the hwc to provide refresh timestamps to the surface flinger.
[android-x86/hardware-intel-hwcomposer.git] / hwcomposer.cpp
1 /*
2  * Copyright (C) 2012 Intel Corporation. All rights reserved.
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
17 #include <hardware/hardware.h>
18 #include <hardware/hwcomposer.h>
19 #include <hardware/gralloc.h>
20
21 #include <gralloc_drm.h>
22 #include <gralloc_drm_priv.h>
23 #include <gralloc_drm_handle.h>
24
25 #include <fcntl.h>
26 #include <errno.h>
27
28 #include <cutils/log.h>
29 #include <cutils/atomic.h>
30
31 #include <hardware/hwcomposer.h>
32
33 #include <EGL/egl.h>
34
35 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
36
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)
43
44 static int hwc_device_open(const struct hw_module_t* module, const char* name,
45                 struct hw_device_t** device);
46
47 static struct hw_module_methods_t hwc_module_methods = {
48         open: hwc_device_open
49 };
50
51 hwc_module_t HAL_MODULE_INFO_SYM = {
52         common: {
53                 tag: HARDWARE_MODULE_TAG,
54                 version_major: 1,
55                 version_minor: 0,
56                 id: HWC_HARDWARE_MODULE_ID,
57                 name: "Intel hwcomposer module",
58                 author: "Intel",
59                 methods: &hwc_module_methods,
60         }
61 };
62
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
120 static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
121         hwc_display_contents_1_t** displays)
122 {
123         struct hwc_context_t* ctx = (struct hwc_context_t *) &dev->common;
124
125         // SurfaceFlinger wants to handle the complete composition
126         if (!displays[0]->hwLayers || displays[0]->numHwLayers == 0)
127                 return 0;
128
129         int topmost = displays[0]->numHwLayers;
130         if (displays[0]->numHwLayers > 0)
131                 topmost--;
132
133         if (displays[0]->hwLayers->flags & HWC_GEOMETRY_CHANGED) {
134                 for (int i=topmost; i>=0; i--) {
135                         displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
136                 }
137         }
138         return 0;
139 }
140
141
142 static int hwc_set(hwc_composer_device_1 *dev,
143                 size_t numDisplays, hwc_display_contents_1_t** displays)
144 {
145         struct hwc_context_t* ctx = (struct hwc_context_t*)dev;
146         EGLBoolean success;
147
148         // display is turning off
149         if (!displays[0]->dpy)
150                 return 0;
151
152         success = eglSwapBuffers((EGLDisplay)displays[0]->dpy,
153                 (EGLSurface)displays[0]->sur);
154
155         if (!success)
156                 return HWC_EGL_ERROR;
157
158         return 0;
159 }
160
161 // toggle display on or off
162 static int hwc_blank(struct hwc_composer_device_1* dev, int disp, int blank)
163 {
164         // dummy implementation for now
165         return 0;
166 }
167
168 // query number of different configurations available on display
169 static int hwc_get_display_cfgs(struct hwc_composer_device_1* dev, int disp,
170         uint32_t* configs, size_t* numConfigs)
171 {
172         // support just one config per display for now
173         *configs = 1;
174         *numConfigs = 1;
175
176         return 0;
177 }
178
179 // query display attributes for a particular config
180 static int hwc_get_display_attrs(struct hwc_composer_device_1* dev, int disp,
181         uint32_t config, const uint32_t* attributes, int32_t* values)
182 {
183         int attr = 0;
184         struct hwc_context_t* ctx = (struct hwc_context_t *) &dev->common;
185
186         gralloc_drm_t *drm = ctx->gralloc_module->drm;
187
188         // support only 1 display for now
189         if (disp > 0)
190                 return -EINVAL;
191
192         while(attributes[attr] != HWC_DISPLAY_NO_ATTRIBUTE) {
193                 switch (attr) {
194                         case HWC_DISPLAY_VSYNC_PERIOD:
195                                 values[attr] = drm->primary.mode.vrefresh;
196                                 break;
197                         case HWC_DISPLAY_WIDTH:
198                                 values[attr] = drm->primary.mode.hdisplay;
199                                 break;
200                         case HWC_DISPLAY_HEIGHT:
201                                 values[attr] = drm->primary.mode.vdisplay;
202                                 break;
203                         case HWC_DISPLAY_DPI_X:
204                                 values[attr] = drm->primary.xdpi;
205                                 break;
206                         case HWC_DISPLAY_DPI_Y:
207                                 values[attr] = drm->primary.ydpi;
208                                 break;
209                 }
210                 attr++;
211         }
212         return 0;
213 }
214
215 static int hwc_device_close(struct hw_device_t *dev)
216 {
217         struct hwc_context_t* ctx = (struct hwc_context_t*)dev;
218
219         if (ctx)
220                 free(ctx);
221
222         if (ctx->vsync_thread != NULL)
223                 ctx->vsync_thread->requestExitAndWait();
224
225         return 0;
226 }
227
228 /*****************************************************************************/
229
230 static int hwc_device_open(const struct hw_module_t* module, const char* name,
231                 struct hw_device_t** device)
232 {
233         int status = -EINVAL;
234         if (strcmp(name, HWC_HARDWARE_COMPOSER))
235                 return status;
236
237         struct hwc_context_t *dev;
238         dev = (hwc_context_t*)calloc(1, sizeof(*dev));
239
240         /* initialize the procs */
241         dev->device.common.tag = HARDWARE_DEVICE_TAG;
242         dev->device.common.version = HWC_DEVICE_API_VERSION_1_0;
243         dev->device.common.module = const_cast<hw_module_t*>(module);
244         dev->device.common.close = hwc_device_close;
245
246         dev->device.prepare = hwc_prepare;
247         dev->device.set = hwc_set;
248         dev->device.blank = hwc_blank;
249         dev->device.getDisplayAttributes = hwc_get_display_attrs;
250         dev->device.getDisplayConfigs = hwc_get_display_cfgs;
251         dev->device.registerProcs = hwc_register_procs;
252         dev->device.eventControl = hwc_event_control;
253
254         *device = &dev->device.common;
255
256         int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
257                 (const hw_module_t **)&dev->gralloc_module);
258
259         dev->vsync_thread = new vsync_worker(*dev);
260
261         ALOGD("Intel hwcomposer module");
262
263         return 0;
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