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