exynos3: Implement custom VSYNC IOCTL
authorMichael Brehm <djp952@gmail.com>
Sat, 15 Sep 2012 07:03:39 +0000 (02:03 -0500)
committerChirayu Desai <chirayudesai1@gmail.com>
Sun, 16 Sep 2012 06:06:05 +0000 (11:36 +0530)
* 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
exynos3/s5pc110/libhwcomposer/Android.mk
exynos3/s5pc110/libhwcomposer/SecHWC.cpp

index 6a3a34ab3b89c79e402397315b284823f4dc2c26..82ef42f1c77674956a32e14a33f771cb071426c5 100755 (executable)
@@ -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)
index defda3ec94464f1ca2388c73018ac184bc2ac04d..a058145024363c6276c41e80fa59e814b8f0e4ef 100644 (file)
@@ -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)
index dda11088bfa884e37c562fba3d1f4f9bf84fb0d6..31d25f49f53d3c207346472b906c9ce4b23c080c 100644 (file)
@@ -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, &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);
 
         bool vsync = !strcmp(uevent_desc, "change@/devices/platform/s3cfb");
         if(vsync)
             handle_vsync_uevent(ctx, uevent_desc, len);
+#endif
     }
 
     return NULL;