hwc.cpp revision 2972485a91007a12d3ad1c6057601ccbf15f01ef
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 17#include <errno.h> 18#include <fcntl.h> 19#include <poll.h> 20#include <pthread.h> 21#include <stdio.h> 22#include <stdlib.h> 23 24#include <sys/ioctl.h> 25#include <sys/mman.h> 26#include <sys/time.h> 27#include <sys/resource.h> 28 29#include <s3c-fb.h> 30 31#include <EGL/egl.h> 32 33#define HWC_REMOVE_DEPRECATED_VERSIONS 1 34 35#include <cutils/log.h> 36#include <hardware/gralloc.h> 37#include <hardware/hardware.h> 38#include <hardware/hwcomposer.h> 39#include <hardware_legacy/uevent.h> 40#include <utils/Vector.h> 41 42#include <sync/sync.h> 43 44#include "ump.h" 45#include "ion.h" 46#include "gralloc_priv.h" 47#include "exynos_gscaler.h" 48 49struct hwc_callback_entry { 50 void (*callback)(void *, private_handle_t *); 51 void *data; 52}; 53typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t; 54 55const size_t NUM_HW_WINDOWS = 5; 56const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1; 57const size_t MAX_PIXELS = 2560 * 1600 * 2; 58 59struct exynos5_hwc_composer_device_1_t; 60 61struct exynos5_hwc_post_data_t { 62 exynos5_hwc_composer_device_1_t *pdev; 63 int overlay_map[NUM_HW_WINDOWS]; 64 hwc_layer_1_t overlays[NUM_HW_WINDOWS]; 65 int num_overlays; 66 size_t fb_window; 67 int fence; 68 pthread_mutex_t completion_lock; 69 pthread_cond_t completion; 70}; 71 72struct exynos5_hwc_composer_device_1_t { 73 hwc_composer_device_1_t base; 74 75 int fd; 76 int vsync_fd; 77 exynos5_hwc_post_data_t bufs; 78 79 const private_module_t *gralloc_module; 80 hwc_procs_t *procs; 81 pthread_t vsync_thread; 82 83 bool hdmi_hpd; 84 bool hdmi_mirroring; 85 void *hdmi_gsc; 86}; 87 88static void dump_layer(hwc_layer_1_t const *l) 89{ 90 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, " 91 "{%d,%d,%d,%d}, {%d,%d,%d,%d}", 92 l->compositionType, l->flags, l->handle, l->transform, 93 l->blending, 94 l->sourceCrop.left, 95 l->sourceCrop.top, 96 l->sourceCrop.right, 97 l->sourceCrop.bottom, 98 l->displayFrame.left, 99 l->displayFrame.top, 100 l->displayFrame.right, 101 l->displayFrame.bottom); 102} 103 104static void dump_handle(private_handle_t *h) 105{ 106 ALOGV("\t\tformat = %d, width = %u, height = %u, bpp = %u, stride = %u", 107 h->format, h->width, h->height, h->bpp, h->stride); 108} 109 110static void dump_config(s3c_fb_win_config &c) 111{ 112 ALOGV("\tstate = %u", c.state); 113 if (c.state == c.S3C_FB_WIN_STATE_BUFFER) { 114 ALOGV("\t\tfd = %d, offset = %u, stride = %u, " 115 "x = %d, y = %d, w = %u, h = %u, " 116 "format = %u", 117 c.fd, c.offset, c.stride, 118 c.x, c.y, c.w, c.h, 119 c.format); 120 } 121 else if (c.state == c.S3C_FB_WIN_STATE_COLOR) { 122 ALOGV("\t\tcolor = %u", c.color); 123 } 124} 125 126inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; } 127inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; } 128template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; } 129template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; } 130 131static bool is_transformed(const hwc_layer_1_t &layer) 132{ 133 return layer.transform != 0; 134} 135 136static bool is_scaled(const hwc_layer_1_t &layer) 137{ 138 return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) || 139 HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop); 140} 141 142static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format) 143{ 144 switch (format) { 145 case HAL_PIXEL_FORMAT_RGBA_8888: 146 return S3C_FB_PIXEL_FORMAT_RGBA_8888; 147 case HAL_PIXEL_FORMAT_RGBX_8888: 148 return S3C_FB_PIXEL_FORMAT_RGBX_8888; 149 case HAL_PIXEL_FORMAT_RGBA_5551: 150 return S3C_FB_PIXEL_FORMAT_RGBA_5551; 151 case HAL_PIXEL_FORMAT_RGBA_4444: 152 return S3C_FB_PIXEL_FORMAT_RGBA_4444; 153 154 default: 155 return S3C_FB_PIXEL_FORMAT_MAX; 156 } 157} 158 159static bool exynos5_format_is_supported(int format) 160{ 161 return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX; 162} 163 164static bool exynos5_format_is_supported_by_gscaler(int format) 165{ 166 switch(format) { 167 case HAL_PIXEL_FORMAT_RGBA_8888: 168 case HAL_PIXEL_FORMAT_RGBX_8888: 169 case HAL_PIXEL_FORMAT_RGB_565: 170 case HAL_PIXEL_FORMAT_YV12: 171 return true; 172 173 default: 174 return false; 175 } 176} 177 178static uint8_t exynos5_format_to_bpp(int format) 179{ 180 switch (format) { 181 case HAL_PIXEL_FORMAT_RGBA_8888: 182 case HAL_PIXEL_FORMAT_RGBX_8888: 183 return 32; 184 185 case HAL_PIXEL_FORMAT_RGBA_5551: 186 case HAL_PIXEL_FORMAT_RGBA_4444: 187 return 16; 188 189 default: 190 ALOGW("unrecognized pixel format %u", format); 191 return 0; 192 } 193} 194 195static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev) 196{ 197 if (dev->hdmi_mirroring) 198 return 0; 199 200 exynos_gsc_img src_info; 201 exynos_gsc_img dst_info; 202 203 // TODO: Don't hardcode 204 int src_w = 2560; 205 int src_h = 1600; 206 int dst_w = 1920; 207 int dst_h = 1080; 208 209 dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV); 210 if (!dev->hdmi_gsc) { 211 ALOGE("%s: exynos_gsc_create_exclusive failed", __func__); 212 return -ENODEV; 213 } 214 215 memset(&src_info, 0, sizeof(src_info)); 216 memset(&dst_info, 0, sizeof(dst_info)); 217 218 src_info.w = src_w; 219 src_info.h = src_h; 220 src_info.fw = src_w; 221 src_info.fh = src_h; 222 src_info.format = HAL_PIXEL_FORMAT_BGRA_8888; 223 224 dst_info.w = dst_w; 225 dst_info.h = dst_h; 226 dst_info.fw = dst_w; 227 dst_info.fh = dst_h; 228 dst_info.format = HAL_PIXEL_FORMAT_YV12; 229 230 int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dst_info); 231 if (ret < 0) { 232 ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret); 233 exynos_gsc_destroy(dev->hdmi_gsc); 234 dev->hdmi_gsc = NULL; 235 return ret; 236 } 237 238 dev->hdmi_mirroring = true; 239 return 0; 240} 241 242static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev) 243{ 244 if (!dev->hdmi_mirroring) 245 return; 246 exynos_gsc_destroy(dev->hdmi_gsc); 247 dev->hdmi_gsc = NULL; 248 dev->hdmi_mirroring = false; 249} 250 251static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb) 252{ 253 exynos_gsc_img src_info; 254 exynos_gsc_img dst_info; 255 256 memset(&src_info, 0, sizeof(src_info)); 257 memset(&dst_info, 0, sizeof(dst_info)); 258 259 src_info.yaddr = fb->fd; 260 261 int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info); 262 if (ret < 0) { 263 ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret); 264 return ret; 265 } 266 267 return 0; 268} 269 270bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) 271{ 272 private_handle_t *handle = private_handle_t::dynamicCast(layer.handle); 273 274 if (!handle) { 275 ALOGV("\tlayer %u: handle is NULL", i); 276 return false; 277 } 278 if (!exynos5_format_is_supported(handle->format)) { 279 ALOGV("\tlayer %u: pixel format %u not supported", i, 280 handle->format); 281 return false; 282 } 283 if (is_scaled(layer)) { 284 ALOGV("\tlayer %u: scaling not supported", i); 285 return false; 286 } 287 if (is_transformed(layer)) { 288 ALOGV("\tlayer %u: transformations not supported", i); 289 return false; 290 } 291 if (layer.blending != HWC_BLENDING_NONE) { 292 // TODO: support this 293 ALOGV("\tlayer %u: blending not supported", i); 294 return false; 295 } 296 297 return true; 298} 299 300inline bool intersect(const hwc_rect &r1, const hwc_rect &r2) 301{ 302 return !(r1.left > r2.right || 303 r1.right < r2.left || 304 r1.top > r2.bottom || 305 r1.bottom < r2.top); 306} 307 308inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2) 309{ 310 hwc_rect i; 311 i.top = max(r1.top, r2.top); 312 i.bottom = min(r1.bottom, r2.bottom); 313 i.left = max(r1.left, r2.left); 314 i.right = min(r1.right, r2.right); 315 return i; 316} 317 318static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) 319{ 320 if (!list) 321 return 0; 322 323 ALOGV("preparing %u layers", list->numHwLayers); 324 325 exynos5_hwc_composer_device_1_t *pdev = 326 (exynos5_hwc_composer_device_1_t *)dev; 327 memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays)); 328 329 bool force_fb = false; 330 if (pdev->hdmi_hpd) { 331 hdmi_enable(pdev); 332 force_fb = true; 333 } else { 334 hdmi_disable(pdev); 335 } 336 337 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) 338 pdev->bufs.overlay_map[i] = -1; 339 340 bool fb_needed = false; 341 size_t first_fb = 0, last_fb = 0; 342 343 // find unsupported overlays 344 for (size_t i = 0; i < list->numHwLayers; i++) { 345 hwc_layer_1_t &layer = list->hwLayers[i]; 346 347 if (layer.compositionType == HWC_BACKGROUND && !force_fb) { 348 ALOGV("\tlayer %u: background supported", i); 349 continue; 350 } 351 352 if (exynos5_supports_overlay(list->hwLayers[i], i) && !force_fb) { 353 ALOGV("\tlayer %u: overlay supported", i); 354 layer.compositionType = HWC_OVERLAY; 355 continue; 356 } 357 358 if (!fb_needed) { 359 first_fb = i; 360 fb_needed = true; 361 } 362 last_fb = i; 363 layer.compositionType = HWC_FRAMEBUFFER; 364 } 365 366 // can't composite overlays sandwiched between framebuffers 367 if (fb_needed) 368 for (size_t i = first_fb; i < last_fb; i++) 369 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; 370 371 // Incrementally try to add our supported layers to hardware windows. 372 // If adding a layer would violate a hardware constraint, force it 373 // into the framebuffer and try again. (Revisiting the entire list is 374 // necessary because adding a layer to the framebuffer can cause other 375 // windows to retroactively violate constraints.) 376 bool changed; 377 do { 378 android::Vector<hwc_rect> rects; 379 android::Vector<hwc_rect> overlaps; 380 size_t pixels_left, windows_left; 381 382 if (fb_needed) { 383 hwc_rect_t fb_rect; 384 fb_rect.top = fb_rect.left = 0; 385 fb_rect.right = pdev->gralloc_module->xres - 1; 386 fb_rect.bottom = pdev->gralloc_module->yres - 1; 387 pixels_left = MAX_PIXELS - pdev->gralloc_module->xres * 388 pdev->gralloc_module->yres; 389 windows_left = NUM_HW_WINDOWS - 1; 390 rects.push_back(fb_rect); 391 } 392 else { 393 pixels_left = MAX_PIXELS; 394 windows_left = NUM_HW_WINDOWS; 395 } 396 changed = false; 397 398 for (size_t i = 0; i < list->numHwLayers; i++) { 399 hwc_layer_1_t &layer = list->hwLayers[i]; 400 401 // we've already accounted for the framebuffer above 402 if (layer.compositionType == HWC_FRAMEBUFFER) 403 continue; 404 405 // only layer 0 can be HWC_BACKGROUND, so we can 406 // unconditionally allow it without extra checks 407 if (layer.compositionType == HWC_BACKGROUND) { 408 windows_left--; 409 continue; 410 } 411 412 size_t pixels_needed = WIDTH(layer.displayFrame) * 413 HEIGHT(layer.displayFrame); 414 bool can_compose = windows_left && pixels_needed <= pixels_left; 415 416 // hwc_rect_t right and bottom values are normally exclusive; 417 // the intersection logic is simpler if we make them inclusive 418 hwc_rect_t visible_rect = layer.displayFrame; 419 visible_rect.right--; visible_rect.bottom--; 420 421 // no more than 2 layers can overlap on a given pixel 422 for (size_t j = 0; can_compose && j < overlaps.size(); j++) { 423 if (intersect(visible_rect, overlaps.itemAt(j))) 424 can_compose = false; 425 } 426 427 if (!can_compose) { 428 layer.compositionType = HWC_FRAMEBUFFER; 429 if (!fb_needed) { 430 first_fb = last_fb = i; 431 fb_needed = true; 432 } 433 else { 434 first_fb = min(i, first_fb); 435 last_fb = max(i, last_fb); 436 } 437 changed = true; 438 break; 439 } 440 441 for (size_t j = 0; j < rects.size(); j++) { 442 const hwc_rect_t &other_rect = rects.itemAt(j); 443 if (intersect(visible_rect, other_rect)) 444 overlaps.push_back(intersection(visible_rect, other_rect)); 445 } 446 rects.push_back(visible_rect); 447 pixels_left -= pixels_needed; 448 windows_left--; 449 } 450 451 if (changed) 452 for (size_t i = first_fb; i < last_fb; i++) 453 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; 454 } while(changed); 455 456 unsigned int nextWindow = 0; 457 458 for (size_t i = 0; i < list->numHwLayers; i++) { 459 hwc_layer_1_t &layer = list->hwLayers[i]; 460 461 if (fb_needed && i == first_fb) { 462 ALOGV("assigning framebuffer to window %u\n", 463 nextWindow); 464 nextWindow++; 465 continue; 466 } 467 468 if (layer.compositionType != HWC_FRAMEBUFFER) { 469 ALOGV("assigning layer %u to window %u", i, nextWindow); 470 pdev->bufs.overlay_map[nextWindow] = i; 471 nextWindow++; 472 } 473 } 474 475 if (fb_needed) 476 pdev->bufs.fb_window = first_fb; 477 else 478 pdev->bufs.fb_window = NO_FB_NEEDED; 479 480 for (size_t i = 0; i < list->numHwLayers; i++) { 481 dump_layer(&list->hwLayers[i]); 482 if(list->hwLayers[i].handle) 483 dump_handle(private_handle_t::dynamicCast( 484 list->hwLayers[i].handle)); 485 } 486 487 return 0; 488} 489 490static void exynos5_config_handle(private_handle_t *handle, 491 hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame, 492 s3c_fb_win_config &cfg) 493{ 494 cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER; 495 cfg.fd = handle->fd; 496 cfg.x = displayFrame.left; 497 cfg.y = displayFrame.top; 498 cfg.w = WIDTH(displayFrame); 499 cfg.h = HEIGHT(displayFrame); 500 cfg.format = exynos5_format_to_s3c_format(handle->format); 501 uint8_t bpp = exynos5_format_to_bpp(handle->format); 502 cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) * bpp / 8; 503 cfg.stride = handle->stride * bpp / 8; 504} 505 506static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg, 507 const private_module_t *gralloc_module) 508{ 509 if (layer->compositionType == HWC_BACKGROUND) { 510 hwc_color_t color = layer->backgroundColor; 511 cfg.state = cfg.S3C_FB_WIN_STATE_COLOR; 512 cfg.color = (color.r << 16) | (color.g << 8) | color.b; 513 cfg.x = 0; 514 cfg.y = 0; 515 cfg.w = gralloc_module->xres; 516 cfg.h = gralloc_module->yres; 517 return; 518 } 519 520 private_handle_t *handle = private_handle_t::dynamicCast(layer->handle); 521 exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame, cfg); 522} 523 524static void exynos5_post_callback(void *data, private_handle_t *fb) 525{ 526 exynos5_hwc_post_data_t *pdata = (exynos5_hwc_post_data_t *)data; 527 528 struct s3c_fb_win_config_data win_data; 529 struct s3c_fb_win_config *config = win_data.config; 530 memset(config, 0, sizeof(win_data.config)); 531 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 532 if (i == pdata->fb_window) { 533 hwc_rect_t rect = { 0, 0, fb->width, fb->height }; 534 exynos5_config_handle(fb, rect, rect, config[i]); 535 } else if ( pdata->overlay_map[i] != -1) { 536 exynos5_config_overlay(&pdata->overlays[i], config[i], 537 pdata->pdev->gralloc_module); 538 if (pdata->overlays[i].acquireFenceFd != -1) { 539 int err = sync_wait(pdata->overlays[i].acquireFenceFd, 100); 540 if (err != 0) 541 ALOGW("fence for layer %zu didn't signal in 100 ms: %s", 542 i, strerror(errno)); 543 close(pdata->overlays[i].acquireFenceFd); 544 } 545 } 546 dump_config(config[i]); 547 } 548 549 int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data); 550 if (ret < 0) 551 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno); 552 553 if (pdata->pdev->hdmi_mirroring) 554 hdmi_output(pdata->pdev, fb); 555 556 pthread_mutex_lock(&pdata->completion_lock); 557 pdata->fence = win_data.fence; 558 pthread_cond_signal(&pdata->completion); 559 pthread_mutex_unlock(&pdata->completion_lock); 560} 561 562static int exynos5_set(struct hwc_composer_device_1 *dev, hwc_display_t dpy, 563 hwc_surface_t sur, hwc_layer_list_1_t* list) 564{ 565 exynos5_hwc_composer_device_1_t *pdev = 566 (exynos5_hwc_composer_device_1_t *)dev; 567 568 if (!dpy || !sur) 569 return 0; 570 571 hwc_callback_queue_t *queue = NULL; 572 pthread_mutex_t *lock = NULL; 573 exynos5_hwc_post_data_t *data = NULL; 574 575 if (list) { 576 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 577 if (pdev->bufs.overlay_map[i] != -1) { 578 pdev->bufs.overlays[i] = 579 list->hwLayers[pdev->bufs.overlay_map[i]]; 580 } 581 } 582 583 data = (exynos5_hwc_post_data_t *) 584 malloc(sizeof(exynos5_hwc_post_data_t)); 585 memcpy(data, &pdev->bufs, sizeof(pdev->bufs)); 586 587 data->fence = -1; 588 pthread_mutex_init(&data->completion_lock, NULL); 589 pthread_cond_init(&data->completion, NULL); 590 591 if (pdev->bufs.fb_window == NO_FB_NEEDED) { 592 exynos5_post_callback(data, NULL); 593 } else { 594 595 struct hwc_callback_entry entry; 596 entry.callback = exynos5_post_callback; 597 entry.data = data; 598 599 queue = reinterpret_cast<hwc_callback_queue_t *>( 600 pdev->gralloc_module->queue); 601 lock = const_cast<pthread_mutex_t *>( 602 &pdev->gralloc_module->queue_lock); 603 604 pthread_mutex_lock(lock); 605 queue->push_front(entry); 606 pthread_mutex_unlock(lock); 607 608 EGLBoolean success = eglSwapBuffers((EGLDisplay)dpy, 609 (EGLSurface)sur); 610 if (!success) { 611 ALOGE("HWC_EGL_ERROR"); 612 if (list) { 613 pthread_mutex_lock(lock); 614 queue->removeAt(0); 615 pthread_mutex_unlock(lock); 616 free(data); 617 } 618 return HWC_EGL_ERROR; 619 } 620 } 621 } 622 623 624 pthread_mutex_lock(&data->completion_lock); 625 while (data->fence == -1) 626 pthread_cond_wait(&data->completion, &data->completion_lock); 627 pthread_mutex_unlock(&data->completion_lock); 628 629 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 630 if (pdev->bufs.overlay_map[i] != -1) { 631 int dup_fd = dup(data->fence); 632 if (dup_fd < 0) 633 ALOGW("release fence dup failed: %s", strerror(errno)); 634 list->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd; 635 } 636 } 637 close(data->fence); 638 free(data); 639 return 0; 640} 641 642static void exynos5_registerProcs(struct hwc_composer_device_1* dev, 643 hwc_procs_t const* procs) 644{ 645 struct exynos5_hwc_composer_device_1_t* pdev = 646 (struct exynos5_hwc_composer_device_1_t*)dev; 647 pdev->procs = const_cast<hwc_procs_t *>(procs); 648} 649 650static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value) 651{ 652 struct exynos5_hwc_composer_device_1_t *pdev = 653 (struct exynos5_hwc_composer_device_1_t *)dev; 654 655 switch (what) { 656 case HWC_BACKGROUND_LAYER_SUPPORTED: 657 // we support the background layer 658 value[0] = 1; 659 break; 660 case HWC_VSYNC_PERIOD: 661 // vsync period in nanosecond 662 value[0] = 1000000000.0 / pdev->gralloc_module->fps; 663 break; 664 default: 665 // unsupported query 666 return -EINVAL; 667 } 668 return 0; 669} 670 671static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int event, 672 int enabled) 673{ 674 struct exynos5_hwc_composer_device_1_t *pdev = 675 (struct exynos5_hwc_composer_device_1_t *)dev; 676 677 switch (event) { 678 case HWC_EVENT_VSYNC: 679 __u32 val = !!enabled; 680 int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val); 681 if (err < 0) { 682 ALOGE("vsync ioctl failed"); 683 return -errno; 684 } 685 686 return 0; 687 } 688 689 return -EINVAL; 690} 691 692static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev, 693 const char *buff, int len) 694{ 695 const char *s = buff; 696 s += strlen(s) + 1; 697 698 while (*s) { 699 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE="))) 700 pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1; 701 702 s += strlen(s) + 1; 703 if (s - buff >= len) 704 break; 705 } 706 707 ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled"); 708 709 if (pdev->procs && pdev->procs->invalidate) 710 pdev->procs->invalidate(pdev->procs); 711} 712 713static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev) 714{ 715 if (!pdev->procs || !pdev->procs->vsync) 716 return; 717 718 char buf[4096]; 719 int err = read(pdev->vsync_fd, buf, sizeof(buf)); 720 if (err < 0) { 721 ALOGE("error reading vsync timestamp: %s", strerror(errno)); 722 return; 723 } 724 buf[sizeof(buf) - 1] = '\0'; 725 726 errno = 0; 727 uint64_t timestamp = strtoull(buf, NULL, 0); 728 if (!errno) 729 pdev->procs->vsync(pdev->procs, 0, timestamp); 730} 731 732static void *hwc_vsync_thread(void *data) 733{ 734 struct exynos5_hwc_composer_device_1_t *pdev = 735 (struct exynos5_hwc_composer_device_1_t *)data; 736 char uevent_desc[4096]; 737 memset(uevent_desc, 0, sizeof(uevent_desc)); 738 739 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); 740 741 uevent_init(); 742 743 struct pollfd fds[2]; 744 fds[0].fd = pdev->vsync_fd; 745 fds[0].events = POLLPRI; 746 fds[1].fd = uevent_get_fd(); 747 fds[1].events = POLLIN; 748 749 while (true) { 750 int err = poll(fds, 2, -1); 751 752 if (err > 0) { 753 if (fds[0].revents & POLLPRI) { 754 handle_vsync_event(pdev); 755 } 756 else if (fds[1].revents & POLLIN) { 757 int len = uevent_next_event(uevent_desc, 758 sizeof(uevent_desc) - 2); 759 760 bool hdmi = !strcmp(uevent_desc, 761 "change@/devices/virtual/switch/hdmi"); 762 if (hdmi) 763 handle_hdmi_uevent(pdev, uevent_desc, len); 764 } 765 } 766 else if (err == -1) { 767 if (errno == EINTR) 768 break; 769 ALOGE("error in vsync thread: %s", strerror(errno)); 770 } 771 } 772 773 return NULL; 774} 775 776static int exynos5_blank(struct hwc_composer_device_1 *dev, int blank) 777{ 778 struct exynos5_hwc_composer_device_1_t *pdev = 779 (struct exynos5_hwc_composer_device_1_t *)dev; 780 781 int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK; 782 int err = ioctl(pdev->fd, FBIOBLANK, fb_blank); 783 if (err < 0) { 784 ALOGE("%sblank ioctl failed", blank ? "" : "un"); 785 return -errno; 786 } 787 788 return 0; 789} 790 791struct hwc_methods_1 exynos5_methods = { 792 eventControl: exynos5_eventControl, 793 blank: exynos5_blank, 794}; 795 796static int exynos5_close(hw_device_t* device); 797 798static int exynos5_open(const struct hw_module_t *module, const char *name, 799 struct hw_device_t **device) 800{ 801 int ret; 802 int sw_fd; 803 804 if (strcmp(name, HWC_HARDWARE_COMPOSER)) { 805 return -EINVAL; 806 } 807 808 struct exynos5_hwc_composer_device_1_t *dev; 809 dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev)); 810 memset(dev, 0, sizeof(*dev)); 811 812 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, 813 (const struct hw_module_t **)&dev->gralloc_module)) { 814 ALOGE("failed to get gralloc hw module"); 815 ret = -EINVAL; 816 goto err_get_module; 817 } 818 819 dev->fd = open("/dev/graphics/fb0", O_RDWR); 820 if (dev->fd < 0) { 821 ALOGE("failed to open framebuffer"); 822 ret = dev->fd; 823 goto err_get_module; 824 } 825 826 dev->vsync_fd = open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY); 827 if (dev->vsync_fd < 0) { 828 ALOGE("failed to open vsync attribute"); 829 ret = dev->vsync_fd; 830 goto err_ioctl; 831 } 832 833 sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY); 834 if (sw_fd) { 835 char val; 836 if (read(sw_fd, &val, 1) == 1 && val == '1') 837 dev->hdmi_hpd = true; 838 } 839 840 dev->base.common.tag = HARDWARE_DEVICE_TAG; 841 dev->base.common.version = HWC_DEVICE_API_VERSION_1_0; 842 dev->base.common.module = const_cast<hw_module_t *>(module); 843 dev->base.common.close = exynos5_close; 844 845 dev->base.prepare = exynos5_prepare; 846 dev->base.set = exynos5_set; 847 dev->base.registerProcs = exynos5_registerProcs; 848 dev->base.query = exynos5_query; 849 dev->base.methods = &exynos5_methods; 850 851 dev->bufs.pdev = dev; 852 853 *device = &dev->base.common; 854 855 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev); 856 if (ret) { 857 ALOGE("failed to start vsync thread: %s", strerror(ret)); 858 ret = -ret; 859 goto err_vsync; 860 } 861 862 return 0; 863 864err_vsync: 865 close(dev->vsync_fd); 866err_ioctl: 867 close(dev->fd); 868err_get_module: 869 free(dev); 870 return ret; 871} 872 873static int exynos5_close(hw_device_t *device) 874{ 875 struct exynos5_hwc_composer_device_1_t *dev = 876 (struct exynos5_hwc_composer_device_1_t *)device; 877 pthread_kill(dev->vsync_thread, SIGTERM); 878 pthread_join(dev->vsync_thread, NULL); 879 close(dev->vsync_fd); 880 close(dev->fd); 881 return 0; 882} 883 884static struct hw_module_methods_t exynos5_hwc_module_methods = { 885 open: exynos5_open, 886}; 887 888hwc_module_t HAL_MODULE_INFO_SYM = { 889 common: { 890 tag: HARDWARE_MODULE_TAG, 891 module_api_version: HWC_MODULE_API_VERSION_0_1, 892 hal_api_version: HARDWARE_HAL_API_VERSION, 893 id: HWC_HARDWARE_MODULE_ID, 894 name: "Samsung exynos5 hwcomposer module", 895 author: "Google", 896 methods: &exynos5_hwc_module_methods, 897 } 898}; 899