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
tirimbino
Michael Brehm 12 years ago committed by Chirayu Desai
parent 317dcfa0f0
commit 3c938a7e18
  1. 1
      exynos3/s5pc110/include/sec_lcd.h
  2. 4
      exynos3/s5pc110/libhwcomposer/Android.mk
  3. 52
      exynos3/s5pc110/libhwcomposer/SecHWC.cpp

@ -34,6 +34,7 @@ struct secfb_user_window {
#define FBIO_WAITFORVSYNC _IO ('F', 32) #define FBIO_WAITFORVSYNC _IO ('F', 32)
#define SECFB_WIN_POSITION _IOW ('F', 203, struct secfb_user_window) #define SECFB_WIN_POSITION _IOW ('F', 203, struct secfb_user_window)
#define S3CFB_SET_VSYNC_INT _IOW ('F', 206, uint32_t) #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_WIDTH (480)
#define DEFAULT_LCD_HEIGHT (800) #define DEFAULT_LCD_HEIGHT (800)

@ -27,6 +27,10 @@ LOCAL_C_INCLUDES := \
LOCAL_SRC_FILES := SecHWCUtils.cpp SecHWC.cpp 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 := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

@ -453,6 +453,17 @@ static int hwc_query(struct hwc_composer_device* dev,
return 0; 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, static int hwc_eventControl(struct hwc_composer_device* dev,
int event, int enabled) int event, int enabled)
{ {
@ -465,6 +476,18 @@ static int hwc_eventControl(struct hwc_composer_device* dev,
if (err < 0) if (err < 0)
return -errno; 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; 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) static void *hwc_vsync_thread(void *data)
{ {
hwc_context_t *ctx = (hwc_context_t *)(data); hwc_context_t *ctx = (hwc_context_t *)(data);
#ifdef VSYNC_IOCTL
uint64_t timestamp = 0;
#else
char uevent_desc[4096]; char uevent_desc[4096];
memset(uevent_desc, 0, sizeof(uevent_desc)); memset(uevent_desc, 0, sizeof(uevent_desc));
#endif
setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
#ifndef VSYNC_IOCTL
uevent_init(); uevent_init();
#endif
while(true) { 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, &timestamp);
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); int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
bool vsync = !strcmp(uevent_desc, "change@/devices/platform/s3cfb"); bool vsync = !strcmp(uevent_desc, "change@/devices/platform/s3cfb");
if(vsync) if(vsync)
handle_vsync_uevent(ctx, uevent_desc, len); handle_vsync_uevent(ctx, uevent_desc, len);
#endif
} }
return NULL; return NULL;

Loading…
Cancel
Save