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 <errno.h> 17#include <pthread.h> 18#include <stdlib.h> 19#include <string.h> 20#include <sys/time.h> 21#include <sys/resource.h> 22#include <unistd.h> 23 24#include <log/log.h> 25#include <hardware/hwcomposer.h> 26#include <sync/sync.h> 27 28struct ranchu_hwc_composer_device_1 { 29 hwc_composer_device_1_t base; // constant after init 30 const hwc_procs_t *procs; // constant after init 31 pthread_t vsync_thread; // constant after init 32 int32_t vsync_period_ns; // constant after init 33 framebuffer_device_t* fbdev; // constant after init 34 35 pthread_mutex_t vsync_lock; 36 bool vsync_callback_enabled; // protected by this->vsync_lock 37}; 38 39static int hwc_prepare(hwc_composer_device_1_t* dev __unused, 40 size_t numDisplays, hwc_display_contents_1_t** displays) { 41 42 if (!numDisplays || !displays) return 0; 43 44 hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY]; 45 46 if (!contents) return 0; 47 48 for (size_t i = 0; i < contents->numHwLayers; i++) { 49 // We do not handle any layers, so set composition type of any non 50 // HWC_FRAMEBUFFER_TARGET layer to to HWC_FRAMEBUFFER. 51 if (contents->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) { 52 continue; 53 } 54 contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER; 55 } 56 return 0; 57} 58 59static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays, 60 hwc_display_contents_1_t** displays) { 61 struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev; 62 if (!numDisplays || !displays) { 63 return 0; 64 } 65 66 hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY]; 67 68 int retireFenceFd = -1; 69 int err = 0; 70 for (size_t layer = 0; layer < contents->numHwLayers; layer++) { 71 hwc_layer_1_t* fb_layer = &contents->hwLayers[layer]; 72 73 int releaseFenceFd = -1; 74 if (fb_layer->acquireFenceFd > 0) { 75 const int kAcquireWarningMS= 3000; 76 err = sync_wait(fb_layer->acquireFenceFd, kAcquireWarningMS); 77 if (err < 0 && errno == ETIME) { 78 ALOGE("hwcomposer waited on fence %d for %d ms", 79 fb_layer->acquireFenceFd, kAcquireWarningMS); 80 } 81 close(fb_layer->acquireFenceFd); 82 83 if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) { 84 ALOGE("hwcomposer found acquire fence on layer %d which is not an" 85 "HWC_FRAMEBUFFER_TARGET layer", layer); 86 } 87 88 releaseFenceFd = dup(fb_layer->acquireFenceFd); 89 fb_layer->acquireFenceFd = -1; 90 } 91 92 if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) { 93 continue; 94 } 95 96 pdev->fbdev->post(pdev->fbdev, fb_layer->handle); 97 fb_layer->releaseFenceFd = releaseFenceFd; 98 99 if (releaseFenceFd > 0) { 100 if (retireFenceFd == -1) { 101 retireFenceFd = dup(releaseFenceFd); 102 } else { 103 int mergedFenceFd = sync_merge("hwc_set retireFence", 104 releaseFenceFd, retireFenceFd); 105 close(retireFenceFd); 106 retireFenceFd = mergedFenceFd; 107 } 108 } 109 } 110 111 contents->retireFenceFd = retireFenceFd; 112 return err; 113} 114 115static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) { 116 struct ranchu_hwc_composer_device_1* pdev = 117 (struct ranchu_hwc_composer_device_1*)dev; 118 119 switch (what) { 120 case HWC_BACKGROUND_LAYER_SUPPORTED: 121 // we do not support the background layer 122 value[0] = 0; 123 break; 124 case HWC_VSYNC_PERIOD: 125 value[0] = pdev->vsync_period_ns; 126 break; 127 default: 128 // unsupported query 129 ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what); 130 return -EINVAL; 131 } 132 return 0; 133} 134 135static int hwc_event_control(struct hwc_composer_device_1* dev, int dpy __unused, 136 int event, int enabled) { 137 struct ranchu_hwc_composer_device_1* pdev = 138 (struct ranchu_hwc_composer_device_1*)dev; 139 int ret = -EINVAL; 140 141 // enabled can only be 0 or 1 142 if (!(enabled & ~1)) { 143 if (event == HWC_EVENT_VSYNC) { 144 pthread_mutex_lock(&pdev->vsync_lock); 145 pdev->vsync_callback_enabled=enabled; 146 pthread_mutex_unlock(&pdev->vsync_lock); 147 ret = 0; 148 } 149 } 150 return ret; 151} 152 153static int hwc_blank(struct hwc_composer_device_1* dev __unused, int disp, 154 int blank __unused) { 155 if (disp != HWC_DISPLAY_PRIMARY) { 156 return -EINVAL; 157 } 158 return 0; 159} 160 161static void hwc_dump(hwc_composer_device_1* dev __unused, char* buff __unused, 162 int buff_len __unused) { 163 // This is run when running dumpsys. 164 // No-op for now. 165} 166 167 168static int hwc_get_display_configs(struct hwc_composer_device_1* dev __unused, 169 int disp, uint32_t* configs, size_t* numConfigs) { 170 if (*numConfigs == 0) { 171 return 0; 172 } 173 174 if (disp == HWC_DISPLAY_PRIMARY) { 175 configs[0] = 0; 176 *numConfigs = 1; 177 return 0; 178 } 179 180 return -EINVAL; 181} 182 183 184static int32_t hwc_attribute(struct ranchu_hwc_composer_device_1* pdev, 185 const uint32_t attribute) { 186 switch(attribute) { 187 case HWC_DISPLAY_VSYNC_PERIOD: 188 return pdev->vsync_period_ns; 189 case HWC_DISPLAY_WIDTH: 190 return pdev->fbdev->width; 191 case HWC_DISPLAY_HEIGHT: 192 return pdev->fbdev->height; 193 case HWC_DISPLAY_DPI_X: 194 return pdev->fbdev->xdpi*1000; 195 case HWC_DISPLAY_DPI_Y: 196 return pdev->fbdev->ydpi*1000; 197 default: 198 ALOGE("unknown display attribute %u", attribute); 199 return -EINVAL; 200 } 201} 202 203static int hwc_get_display_attributes(struct hwc_composer_device_1* dev __unused, 204 int disp, uint32_t config __unused, 205 const uint32_t* attributes, int32_t* values) { 206 207 struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev; 208 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { 209 if (disp == HWC_DISPLAY_PRIMARY) { 210 values[i] = hwc_attribute(pdev, attributes[i]); 211 if (values[i] == -EINVAL) { 212 return -EINVAL; 213 } 214 } else { 215 ALOGE("unknown display type %u", disp); 216 return -EINVAL; 217 } 218 } 219 220 return 0; 221} 222 223static int hwc_close(hw_device_t* dev) { 224 struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev; 225 pthread_kill(pdev->vsync_thread, SIGTERM); 226 pthread_join(pdev->vsync_thread, NULL); 227 free(dev); 228 return 0; 229} 230 231static void* hwc_vsync_thread(void* data) { 232 struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)data; 233 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); 234 235 struct timespec rt; 236 if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) { 237 ALOGE("%s:%d error in vsync thread clock_gettime: %s", 238 __FILE__, __LINE__, strerror(errno)); 239 } 240 const int log_interval = 60; 241 int64_t last_logged = rt.tv_sec; 242 int sent = 0; 243 int last_sent = 0; 244 bool vsync_enabled = false; 245 struct timespec wait_time; 246 wait_time.tv_sec = 0; 247 wait_time.tv_nsec = pdev->vsync_period_ns; 248 249 while (true) { 250 int err = nanosleep(&wait_time, NULL); 251 if (err == -1) { 252 if (errno == EINTR) { 253 break; 254 } 255 ALOGE("error in vsync thread: %s", strerror(errno)); 256 } 257 258 pthread_mutex_lock(&pdev->vsync_lock); 259 vsync_enabled = pdev->vsync_callback_enabled; 260 pthread_mutex_unlock(&pdev->vsync_lock); 261 262 if (!vsync_enabled) { 263 continue; 264 } 265 266 if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) { 267 ALOGE("%s:%d error in vsync thread clock_gettime: %s", 268 __FILE__, __LINE__, strerror(errno)); 269 } 270 271 int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec; 272 pdev->procs->vsync(pdev->procs, 0, timestamp); 273 if (rt.tv_sec - last_logged >= log_interval) { 274 ALOGD("hw_composer sent %d syncs in %ds", sent - last_sent, rt.tv_sec - last_logged); 275 last_logged = rt.tv_sec; 276 last_sent = sent; 277 } 278 ++sent; 279 } 280 281 return NULL; 282} 283 284static void hwc_register_procs(struct hwc_composer_device_1* dev, 285 hwc_procs_t const* procs) { 286 struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev; 287 pdev->procs = procs; 288} 289 290static int hwc_open(const struct hw_module_t* module, const char* name, 291 struct hw_device_t** device) { 292 int ret = 0; 293 294 if (strcmp(name, HWC_HARDWARE_COMPOSER)) { 295 ALOGE("%s called with bad name %s", __FUNCTION__, name); 296 return -EINVAL; 297 } 298 299 ranchu_hwc_composer_device_1 *pdev = new ranchu_hwc_composer_device_1(); 300 if (!pdev) { 301 ALOGE("%s failed to allocate dev", __FUNCTION__); 302 return -ENOMEM; 303 } 304 305 pdev->base.common.tag = HARDWARE_DEVICE_TAG; 306 pdev->base.common.version = HWC_DEVICE_API_VERSION_1_1; 307 pdev->base.common.module = const_cast<hw_module_t *>(module); 308 pdev->base.common.close = hwc_close; 309 310 pdev->base.prepare = hwc_prepare; 311 pdev->base.set = hwc_set; 312 pdev->base.eventControl = hwc_event_control; 313 pdev->base.blank = hwc_blank; 314 pdev->base.query = hwc_query; 315 pdev->base.registerProcs = hwc_register_procs; 316 pdev->base.dump = hwc_dump; 317 pdev->base.getDisplayConfigs = hwc_get_display_configs; 318 pdev->base.getDisplayAttributes = hwc_get_display_attributes; 319 320 pdev->vsync_period_ns = 1000*1000*1000/60; // vsync is 60 hz 321 322 hw_module_t const* hw_module; 323 ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module); 324 if (ret != 0) { 325 ALOGE("ranchu_hw_composer hwc_open %s module not found", GRALLOC_HARDWARE_MODULE_ID); 326 return ret; 327 } 328 ret = framebuffer_open(hw_module, &pdev->fbdev); 329 if (ret != 0) { 330 ALOGE("ranchu_hw_composer hwc_open could not open framebuffer"); 331 } 332 333 pthread_mutex_init(&pdev->vsync_lock, NULL); 334 pdev->vsync_callback_enabled = false; 335 336 ret = pthread_create (&pdev->vsync_thread, NULL, hwc_vsync_thread, pdev); 337 if (ret) { 338 ALOGE("ranchu_hw_composer could not start vsync_thread\n"); 339 } 340 341 *device = &pdev->base.common; 342 343 return ret; 344} 345 346 347static struct hw_module_methods_t hwc_module_methods = { 348 open: hwc_open, 349}; 350 351hwc_module_t HAL_MODULE_INFO_SYM = { 352 common: { 353 tag: HARDWARE_MODULE_TAG, 354 module_api_version: HWC_MODULE_API_VERSION_0_1, 355 hal_api_version: HARDWARE_HAL_API_VERSION, 356 id: HWC_HARDWARE_MODULE_ID, 357 name: "Android Emulator hwcomposer module", 358 author: "The Android Open Source Project", 359 methods: &hwc_module_methods, 360 } 361}; 362