From 3c938a7e18ab2e06b3d925fdc99e157ad125f6bb Mon Sep 17 00:00:00 2001 From: Michael Brehm Date: Sat, 15 Sep 2012 02:03:39 -0500 Subject: [PATCH] exynos3: Implement custom VSYNC IOCTL * Replace crespo-based VSYNC uevent mechanism in hwcomposer with a custom IOCTL mechanism instead (required kernel modifications. * The VSYNC uevents were spamming the Android UEventObserver and causing about 7% of constant CPU load c86856efabfa0b2981ceb47898dc5873a4998707 Improve custom VSYNC handler in hwcomposer * only poll when necessary * solves suspend/resume instability? 45bf1dae7fa9057a3415151f7559e7bd2a162ead Change-Id: Icdb5c60059e71688479d390b7b3a1f09a0315a5f --- exynos3/s5pc110/include/sec_lcd.h | 1 + exynos3/s5pc110/libhwcomposer/Android.mk | 4 ++ exynos3/s5pc110/libhwcomposer/SecHWC.cpp | 52 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/exynos3/s5pc110/include/sec_lcd.h b/exynos3/s5pc110/include/sec_lcd.h index 6a3a34ab..82ef42f1 100755 --- a/exynos3/s5pc110/include/sec_lcd.h +++ b/exynos3/s5pc110/include/sec_lcd.h @@ -34,6 +34,7 @@ struct secfb_user_window { #define FBIO_WAITFORVSYNC _IO ('F', 32) #define SECFB_WIN_POSITION _IOW ('F', 203, struct secfb_user_window) #define S3CFB_SET_VSYNC_INT _IOW ('F', 206, uint32_t) +#define S3CFB_WAIT_FOR_VSYNC _IOR ('F', 311, uint64_t) #define DEFAULT_LCD_WIDTH (480) #define DEFAULT_LCD_HEIGHT (800) diff --git a/exynos3/s5pc110/libhwcomposer/Android.mk b/exynos3/s5pc110/libhwcomposer/Android.mk index defda3ec..a0581450 100644 --- a/exynos3/s5pc110/libhwcomposer/Android.mk +++ b/exynos3/s5pc110/libhwcomposer/Android.mk @@ -27,6 +27,10 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := SecHWCUtils.cpp SecHWC.cpp +ifeq ($(BOARD_CUSTOM_VSYNC_IOCTL),true) + LOCAL_CFLAGS += -DVSYNC_IOCTL +endif + LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/exynos3/s5pc110/libhwcomposer/SecHWC.cpp b/exynos3/s5pc110/libhwcomposer/SecHWC.cpp index dda11088..31d25f49 100644 --- a/exynos3/s5pc110/libhwcomposer/SecHWC.cpp +++ b/exynos3/s5pc110/libhwcomposer/SecHWC.cpp @@ -453,6 +453,17 @@ static int hwc_query(struct hwc_composer_device* dev, return 0; } +#ifdef VSYNC_IOCTL +// Linux version of a manual reset event to control when +// and when not to ask the video card for a VSYNC. This +// stops the worker thread from asking for a VSYNC when +// there is nothing useful to do with it and more closely +// mimicks the original uevent mechanism +int vsync_enable = 0; +pthread_mutex_t vsync_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t vsync_condition = PTHREAD_COND_INITIALIZER; +#endif + static int hwc_eventControl(struct hwc_composer_device* dev, int event, int enabled) { @@ -465,6 +476,18 @@ static int hwc_eventControl(struct hwc_composer_device* dev, if (err < 0) return -errno; +#if VSYNC_IOCTL + // Enable or disable the ability for the worker thread + // to ask for VSYNC events from the video driver + pthread_mutex_lock(&vsync_mutex); + if(enabled) { + vsync_enable = 1; + pthread_cond_broadcast(&vsync_condition); + } + else vsync_enable = 0; + pthread_mutex_unlock(&vsync_mutex); +#endif + return 0; } @@ -496,18 +519,47 @@ void handle_vsync_uevent(hwc_context_t *ctx, const char *buff, int len) static void *hwc_vsync_thread(void *data) { hwc_context_t *ctx = (hwc_context_t *)(data); +#ifdef VSYNC_IOCTL + uint64_t timestamp = 0; +#else char uevent_desc[4096]; memset(uevent_desc, 0, sizeof(uevent_desc)); +#endif setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); +#ifndef VSYNC_IOCTL uevent_init(); +#endif while(true) { +#ifdef VSYNC_IOCTL + // Only continue if hwc_eventControl is enabled, otherwise + // just sit here and wait until it is. This stops the code + // from constantly looking for the VSYNC event with the screen + // turned off. + pthread_mutex_lock(&vsync_mutex); + if(!vsync_enable) pthread_cond_wait(&vsync_condition, &vsync_mutex); + pthread_mutex_unlock(&vsync_mutex); + + timestamp = 0; // Reset the timestamp value + + // S3CFB_WAIT_FOR_VSYNC is a custom IOCTL I added to wait for + // the VSYNC interrupt, and then return the timestamp that was + // originally being communicated via a uevent. The uevent was + // spamming the UEventObserver and events/0 process with more + // information than this device could really deal with every 18ms + int res = ioctl(ctx->global_lcd_win.fd, S3CFB_WAIT_FOR_VSYNC, ×tamp); + if(res > 0) { + if(!ctx->procs || !ctx->procs->vsync) continue; + ctx->procs->vsync(ctx->procs, 0, timestamp); + } +#else int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2); bool vsync = !strcmp(uevent_desc, "change@/devices/platform/s3cfb"); if(vsync) handle_vsync_uevent(ctx, uevent_desc, len); +#endif } return NULL;