summaryrefslogtreecommitdiffstats
path: root/hwc/sw_vsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'hwc/sw_vsync.c')
-rw-r--r--hwc/sw_vsync.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/hwc/sw_vsync.c b/hwc/sw_vsync.c
new file mode 100644
index 0000000..cf24b31
--- /dev/null
+++ b/hwc/sw_vsync.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#include <utils/Timers.h>
+
+#include "hwc_dev.h"
+
+static pthread_t vsync_thread;
+static pthread_mutex_t vsync_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t vsync_cond;
+static bool vsync_loop_active = false;
+
+nsecs_t vsync_rate;
+
+static struct timespec diff(struct timespec start, struct timespec end)
+{
+ struct timespec temp;
+ if ((end.tv_nsec - start.tv_nsec) < 0) {
+ temp.tv_sec = end.tv_sec-start.tv_sec - 1;
+ temp.tv_nsec = 1000000000 + end.tv_nsec-start.tv_nsec;
+ } else {
+ temp.tv_sec = end.tv_sec - start.tv_sec;
+ temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+ }
+ return temp;
+}
+
+static void *vsync_loop(void *data)
+{
+ struct timespec tp, tp_next, tp_sleep;
+ nsecs_t now = 0, period = vsync_rate, next_vsync = 0, next_fake_vsync = 0, sleep = 0;
+ omap_hwc_device_t *hwc_dev = (omap_hwc_device_t *)data;
+ tp_sleep.tv_sec = tp_sleep.tv_nsec = 0;
+ bool reset_timers = true;
+
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+ for (;;) {
+ pthread_mutex_lock(&vsync_mutex);
+ period = vsync_rate; /* re-read rate */
+ while (!vsync_loop_active) {
+ pthread_cond_wait(&vsync_cond, &vsync_mutex);
+ }
+ pthread_mutex_unlock(&vsync_mutex);
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ now = (tp.tv_sec * 1000000000) + tp.tv_nsec;
+ next_vsync = next_fake_vsync;
+ sleep = next_vsync - now;
+ if (sleep < 0) {
+ /* we missed, find where the next vsync should be */
+ sleep = (period - ((now - next_vsync) % period));
+ next_vsync = now + sleep;
+ }
+ next_fake_vsync = next_vsync + period;
+ tp_next.tv_sec = (next_vsync / 1000000000);
+ tp_next.tv_nsec = (next_vsync % 1000000000);
+ tp_sleep = diff(tp, tp_next);
+
+ nanosleep(&tp_sleep, NULL);
+ if (hwc_dev->procs && hwc_dev->procs->vsync) {
+ hwc_dev->procs->vsync(hwc_dev->procs, 0, next_vsync);
+ }
+ }
+ return NULL;
+}
+
+bool use_sw_vsync()
+{
+ char board[PROPERTY_VALUE_MAX];
+ bool rv = false;
+ property_get("ro.product.board", board, "");
+ if ((strncmp("blaze", board, PROPERTY_VALUE_MAX) == 0) ||
+ (strncmp("panda5", board, PROPERTY_VALUE_MAX) == 0)) {
+ /* TODO: panda5 really should support h/w vsync */
+ rv = true;
+ } else {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("persist.hwc.sw_vsync", value, "0");
+ int use_sw_vsync = atoi(value);
+ rv = use_sw_vsync > 0;
+ }
+ ALOGI("Expecting %s vsync for %s", rv ? "s/w" : "h/w", board);
+ return rv;
+}
+
+void init_sw_vsync(omap_hwc_device_t *hwc_dev)
+{
+ pthread_cond_init(&vsync_cond, NULL);
+ pthread_create(&vsync_thread, NULL, vsync_loop, (void *)hwc_dev);
+}
+
+void start_sw_vsync()
+{
+ char refresh_rate[PROPERTY_VALUE_MAX];
+ property_get("persist.hwc.sw_vsync_rate", refresh_rate, "60");
+
+ pthread_mutex_lock(&vsync_mutex);
+ int rate = atoi(refresh_rate);
+ if (rate <= 0)
+ rate = 60;
+ vsync_rate = 1000000000 / rate;
+ if (vsync_loop_active) {
+ pthread_mutex_unlock(&vsync_mutex);
+ return;
+ }
+ vsync_loop_active = true;
+ pthread_mutex_unlock(&vsync_mutex);
+ pthread_cond_signal(&vsync_cond);
+}
+
+void stop_sw_vsync()
+{
+ pthread_mutex_lock(&vsync_mutex);
+ if (!vsync_loop_active) {
+ pthread_mutex_unlock(&vsync_mutex);
+ return;
+ }
+ vsync_loop_active = false;
+ pthread_mutex_unlock(&vsync_mutex);
+ pthread_cond_signal(&vsync_cond);
+}