From d43c7ffa7132f9cc3ec590aa78bc6ed54efe125c Mon Sep 17 00:00:00 2001 From: korejan Date: Tue, 22 Mar 2022 12:33:30 +0000 Subject: [PATCH] android: Support for using device's set display refresh rate * Adds support for querying the device's currently set display refresh rate to be used for android driver on creation. Allowing for devices which support selecting other refresh rate modes beyond 60hz. * Changes hardcoded sensor polling rate to now match refresh queried from the device. --- .../auxiliary/android/android_custom_surface.cpp | 8 +++++++- .../auxiliary/android/android_custom_surface.h | 1 + .../android/org.freedesktop.monado.auxiliary.cpp | 1 + .../android/org.freedesktop.monado.auxiliary.hpp | 13 +++++++++++++ .../org.freedesktop.monado.auxiliary.impl.hpp | 6 ++++++ .../freedesktop/monado/auxiliary/MonadoView.java | 5 +++++ src/xrt/drivers/android/android_sensors.c | 16 ++++++++++++++-- 7 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/android/android_custom_surface.cpp b/src/xrt/auxiliary/android/android_custom_surface.cpp index eacfabe1c..50681155e 100644 --- a/src/xrt/auxiliary/android/android_custom_surface.cpp +++ b/src/xrt/auxiliary/android/android_custom_surface.cpp @@ -175,6 +175,11 @@ android_custom_surface_get_display_metrics(struct _JavaVM *vm, MonadoView::staticInitClass((jclass)clazz.object().getHandle()); jni::Object displayMetrics = MonadoView::getDisplayMetrics(Activity((jobject)activity)); + //! @todo implement non-deprecated codepath for api 30+ + float displayRefreshRate = MonadoView::getDisplayRefreshRate(Activity((jobject)activity)); + if (displayRefreshRate == 0.0) { + displayRefreshRate = 60.0f; + } *out_metrics = {.width_pixels = displayMetrics.get("widthPixels"), .height_pixels = displayMetrics.get("heightPixels"), @@ -182,7 +187,8 @@ android_custom_surface_get_display_metrics(struct _JavaVM *vm, .density = displayMetrics.get("xdpi"), .scaled_density = displayMetrics.get("ydpi"), .xdpi = displayMetrics.get("density"), - .ydpi = displayMetrics.get("scaledDensity")}; + .ydpi = displayMetrics.get("scaledDensity"), + .refresh_rate = displayRefreshRate}; return true; } catch (std::exception const &e) { diff --git a/src/xrt/auxiliary/android/android_custom_surface.h b/src/xrt/auxiliary/android/android_custom_surface.h index f42126a49..a82b3cd13 100644 --- a/src/xrt/auxiliary/android/android_custom_surface.h +++ b/src/xrt/auxiliary/android/android_custom_surface.h @@ -32,6 +32,7 @@ struct xrt_android_display_metrics float scaled_density; float xdpi; float ydpi; + float refresh_rate; }; /*! diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp index 2d44d1149..2625df3e6 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp @@ -20,6 +20,7 @@ namespace org::freedesktop::monado::auxiliary { "attachToActivity", "(Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/MonadoView;")), getDisplayMetrics(classRef().getStaticMethod("getDisplayMetrics", "(Landroid/app/Activity;)Landroid/util/DisplayMetrics;")), + getDisplayRefreshRate(classRef().getStaticMethod("getDisplayRefreshRate", "(Landroid/app/Activity;)F")), getNativePointer(classRef().getMethod("getNativePointer", "()J")), markAsDiscardedByNative(classRef().getMethod("markAsDiscardedByNative", "()V")), waitGetSurfaceHolder(classRef().getMethod("waitGetSurfaceHolder", "(I)Landroid/view/SurfaceHolder;")) diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp index 909c11988..57209bd51 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp @@ -86,6 +86,18 @@ namespace org::freedesktop::monado::auxiliary { static jni::Object getDisplayMetrics(android::app::Activity const &activity); + /*! + * Wrapper for the getDisplayRefreshRate static method + * + * Java prototype: + * `public static float getDisplayRefreshRate(android.app.Activity);` + * + * JNI signature: (Landroid/app/Activity;)F; + * + */ + static float + getDisplayRefreshRate(android::app::Activity const &activity); + /*! * Wrapper for the getNativePointer method * @@ -140,6 +152,7 @@ namespace org::freedesktop::monado::auxiliary { jni::method_t attachToActivity; jni::method_t attachToActivity1; jni::method_t getDisplayMetrics; + jni::method_t getDisplayRefreshRate; jni::method_t getNativePointer; jni::method_t markAsDiscardedByNative; jni::method_t waitGetSurfaceHolder; diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp index a34f3fa6c..bc0f44339 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp @@ -37,6 +37,12 @@ namespace org::freedesktop::monado::auxiliary { return Meta::data().clazz().call(Meta::data().getDisplayMetrics, activity.object()); } + inline float + MonadoView::getDisplayRefreshRate(android::app::Activity const &activity) + { + return Meta::data().clazz().call(Meta::data().getDisplayRefreshRate, activity.object()); + } + inline void * MonadoView::getNativePointer() { diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 029b3e34a..83f68924f 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -106,6 +106,11 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S return displayMetrics; } + @Keep + public static float getDisplayRefreshRate(Activity activity) { + return activity.getWindowManager().getDefaultDisplay().getRefreshRate(); + } + @Keep public long getNativePointer() { if (nativeCounterpart == null) { diff --git a/src/xrt/drivers/android/android_sensors.c b/src/xrt/drivers/android/android_sensors.c index 599f2617f..0e9ab5961 100644 --- a/src/xrt/drivers/android/android_sensors.c +++ b/src/xrt/drivers/android/android_sensors.c @@ -82,10 +82,19 @@ android_sensor_callback(int fd, int events, void *data) return 1; } +static inline int32_t +android_get_sensor_poll_rate(const struct android_device *d) +{ + const float freq_multiplier = 3.0f; + return (d == NULL) ? POLL_RATE_USEC + : (int32_t)(d->base.hmd->screens[0].nominal_frame_interval_ns * freq_multiplier * 0.001f); +} + static void * android_run_thread(void *ptr) { struct android_device *d = (struct android_device *)ptr; + const int32_t poll_rate_usec = android_get_sensor_poll_rate(d); #if __ANDROID_API__ >= 26 d->sensor_manager = ASensorManager_getInstanceForPackage(XRT_ANDROID_PACKAGE); @@ -104,11 +113,11 @@ android_run_thread(void *ptr) // Start sensors in case this was not done already. if (d->accelerometer != NULL) { ASensorEventQueue_enableSensor(d->event_queue, d->accelerometer); - ASensorEventQueue_setEventRate(d->event_queue, d->accelerometer, POLL_RATE_USEC); + ASensorEventQueue_setEventRate(d->event_queue, d->accelerometer, poll_rate_usec); } if (d->gyroscope != NULL) { ASensorEventQueue_enableSensor(d->event_queue, d->gyroscope); - ASensorEventQueue_setEventRate(d->event_queue, d->gyroscope, POLL_RATE_USEC); + ASensorEventQueue_setEventRate(d->event_queue, d->gyroscope, poll_rate_usec); } int ret = 0; @@ -234,8 +243,11 @@ android_device_create() metrics.width_pixels = 2960; metrics.height_pixels = 1440; metrics.density_dpi = 572; + metrics.refresh_rate = 60.0f; } + d->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / metrics.refresh_rate); + const uint32_t w_pixels = metrics.width_pixels; const uint32_t h_pixels = metrics.height_pixels; const uint32_t ppi = metrics.density_dpi;