2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <hardware/hardware.h>
18 #include <hardware/hwcomposer.h>
19 #include <hardware/gralloc.h>
21 #include <gralloc_drm.h>
22 #include <gralloc_drm_priv.h>
23 #include <gralloc_drm_handle.h>
28 #include <cutils/log.h>
29 #include <cutils/atomic.h>
31 #include <hardware/hwcomposer.h>
35 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
37 #include <Condition.h>
40 #include <StrongPointer.h>
42 #define SEC_TO_NANOSEC (1000 * 1000 * 1000)
44 static int hwc_device_open(const struct hw_module_t* module, const char* name,
45 struct hw_device_t** device);
47 static struct hw_module_methods_t hwc_module_methods = {
51 hwc_module_t HAL_MODULE_INFO_SYM = {
53 tag: HARDWARE_MODULE_TAG,
56 id: HWC_HARDWARE_MODULE_ID,
57 name: "Intel hwcomposer module",
59 methods: &hwc_module_methods,
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.
71 class vsync_worker : public android::Thread {
73 vsync_worker(struct hwc_context_t& hwc);
74 void set_enabled(bool enabled);
76 virtual void onFirstRef();
77 virtual bool threadLoop();
78 void wait_until_enabled();
80 struct hwc_context_t& dev;
81 mutable android::Mutex lock;
82 android::Condition condition;
84 mutable int64_t next_fake_vsync;
85 int64_t refresh_period;
88 struct hwc_context_t {
89 hwc_composer_device_1 device;
90 struct drm_module_t *gralloc_module;
92 android::sp<vsync_worker> vsync_thread;
95 static void hwc_register_procs(hwc_composer_device_1 *dev,
96 hwc_procs_t const* procs)
98 struct hwc_context_t* ctx = (struct hwc_context_t*)dev;
99 ctx->procs = (hwc_procs_t *) procs;
102 static int hwc_event_control(hwc_composer_device_1 *dev, int disp, int event,
105 hwc_context_t* ctx = (hwc_context_t*)dev;
108 * The API restricts 'enabled' as having boolean values only. Also for
109 * now there can be only one fixed display having identifier zero.
111 if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1) || disp)
114 if (ctx->vsync_thread != NULL)
115 ctx->vsync_thread->set_enabled(enabled);
120 static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
121 hwc_display_contents_1_t** displays)
123 struct hwc_context_t* ctx = (struct hwc_context_t *) &dev->common;
125 // SurfaceFlinger wants to handle the complete composition
126 if (!displays[0]->hwLayers || displays[0]->numHwLayers == 0)
129 int topmost = displays[0]->numHwLayers;
130 if (displays[0]->numHwLayers > 0)
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;
142 static int hwc_set(hwc_composer_device_1 *dev,
143 size_t numDisplays, hwc_display_contents_1_t** displays)
145 struct hwc_context_t* ctx = (struct hwc_context_t*)dev;
148 // display is turning off
149 if (!displays[0]->dpy)
152 success = eglSwapBuffers((EGLDisplay)displays[0]->dpy,
153 (EGLSurface)displays[0]->sur);
156 return HWC_EGL_ERROR;
161 // toggle display on or off
162 static int hwc_blank(struct hwc_composer_device_1* dev, int disp, int blank)
164 // dummy implementation for now
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)
172 // support just one config per display for now
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)
184 struct hwc_context_t* ctx = (struct hwc_context_t *) &dev->common;
186 gralloc_drm_t *drm = ctx->gralloc_module->drm;
188 // support only 1 display for now
192 while(attributes[attr] != HWC_DISPLAY_NO_ATTRIBUTE) {
194 case HWC_DISPLAY_VSYNC_PERIOD:
195 values[attr] = drm->primary.mode.vrefresh;
197 case HWC_DISPLAY_WIDTH:
198 values[attr] = drm->primary.mode.hdisplay;
200 case HWC_DISPLAY_HEIGHT:
201 values[attr] = drm->primary.mode.vdisplay;
203 case HWC_DISPLAY_DPI_X:
204 values[attr] = drm->primary.xdpi;
206 case HWC_DISPLAY_DPI_Y:
207 values[attr] = drm->primary.ydpi;
215 static int hwc_device_close(struct hw_device_t *dev)
217 struct hwc_context_t* ctx = (struct hwc_context_t*)dev;
222 if (ctx->vsync_thread != NULL)
223 ctx->vsync_thread->requestExitAndWait();
228 /*****************************************************************************/
230 static int hwc_device_open(const struct hw_module_t* module, const char* name,
231 struct hw_device_t** device)
233 int status = -EINVAL;
234 if (strcmp(name, HWC_HARDWARE_COMPOSER))
237 struct hwc_context_t *dev;
238 dev = (hwc_context_t*)calloc(1, sizeof(*dev));
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;
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;
254 *device = &dev->device.common;
256 int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
257 (const hw_module_t **)&dev->gralloc_module);
259 dev->vsync_thread = new vsync_worker(*dev);
261 ALOGD("Intel hwcomposer module");
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);
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
275 vsync_worker::vsync_worker(struct hwc_context_t& mydev)
276 : dev(mydev), enabled(false), next_fake_vsync(0)
279 framebuffer_device_t* fbdev;
281 int err = framebuffer_open((const hw_module_t *)dev.gralloc_module, &fbdev);
283 ALOGE("framebuffer_open failed (%s)", strerror(-err));
285 refresh = int64_t(SEC_TO_NANOSEC / fbdev->fps);
288 refresh = int64_t(SEC_TO_NANOSEC / 60.0);
289 ALOGW("getting VSYNC period from thin air: %lld", refresh);
291 ALOGW("getting VSYNC period from fb HAL: %lld", refresh);
293 refresh_period = refresh;
296 void vsync_worker::set_enabled(bool _enabled)
298 android::Mutex::Autolock _l(lock);
299 if (enabled != _enabled) {
305 void vsync_worker::wait_until_enabled()
307 android::Mutex::Autolock _l(lock);
310 condition.wait(lock);
314 void vsync_worker::onFirstRef()
316 run("vsync_thread", android::PRIORITY_URGENT_DISPLAY +
317 android::PRIORITY_MORE_FAVORABLE);
320 bool vsync_worker::threadLoop()
322 wait_until_enabled();
324 const int64_t now = systemTime(CLOCK_MONOTONIC);
325 int64_t next_vsync = next_fake_vsync;
326 int64_t sleep = next_vsync - now;
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;
334 next_fake_vsync = next_vsync + refresh_period;
336 struct timespec spec;
337 spec.tv_sec = next_vsync / SEC_TO_NANOSEC;
338 spec.tv_nsec = next_vsync % SEC_TO_NANOSEC;
342 err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
343 } while (err < 0 && errno == EINTR);
346 dev.procs->vsync(dev.procs, 0, next_vsync);
348 ALOGE("clock_nanosleep failed with error %d ", err);