Android N VR代码简析

虽然Google早在2016的IO大会上就说DayDream会随着Android N发布,但是从Android N的前几个版本的代码来看,都是没有集成的,直到Android-7.0.0_r14这个版本,才可以看到DayDream的一些简单代码,跟之前预见的一样,DayDream跟三星的GearVR采用的是同样的架构,都分离出来一个单独的VR SDK,比如三星的Oculus SDK,Google的Google VR SDK,应用基于他们的SDK开发应用程序,然后运行在支持这些SDK的Android系统上面。

单独分离出一个SDK,除了方便应用开发者之外,主要的目的是用来把VR的一些核心算法隐藏起来,比如用来减少延迟的ATW异步时间扭曲算法就是被封装在这里,是闭源不公开的,众所周知,在手机上面运行VR的时候一个最大的挑战就是延迟,当一副画面的延迟超过20MS,人就会感觉不舒服恶心,严重影响用户体验,一个好的VR产品都会尽量避免延迟。目前在Mobile VR上主要有以下几种方式来减少延迟:

1、 硬件层面的优化

  • 提升传感器的采样频率,减少刷新率与传感器频率的同步等待时间消耗。
  • 提升传感器的精度, 减少对采样数据进行稳定性过滤产生的延迟。
  • 采用有线传输也有一部分原因是出于延迟的考虑。
  • 屏幕使用OLED替代LCD, 减少像素颜色切换的时间。
  • 提升屏幕刷新率, 主流的屏幕是60Hz, 那每帧就是16.67ms; 如果提升到90Hz, 那每帧就是11.11ms.
  • 双GPU渲染,一个GPU负责左眼的画面,一个GPU负责右眼的渲染。

2、 软件层面的优化

  • 多分辨率渲染,VR画面的中心部分可以高分辨率渲染,周边部分低分辨率渲染
  • 上面提过的ATW算法,一个具有高优先级的线程,以一定的帧率,不断的根据Android渲染出来的画面生
    成一个新的画面,然后投递到屏幕。
  • Front Buffer Render,即只有一个render buffer,应用赶在下一个屏幕刷新周期到来之前把画面更新到这个render buffer,然后屏幕使用这个render buffer更新显示内容,这个需要修改GPU和Display的Driver部分代码。

Android N的DayDream对硬件和软件的一些需求,其实都是根据上面这些优化手段提出来的,具体到Android N的代码来说,它提供了一个SDK,应该是解决了ATW算法和多分辨率渲染等优化问题,然后新增了一个系统服务VrManagerService和 vr HAL层, 应用通过VrManagerService来设置系统进入VR模式,VrManagerService又是通过vr HAL层去实现具体模式的切换的。

Implement this HAL to receive callbacks when a virtual reality (VR)
application is being used. VR applications characteristically have a number of special display and performance requirements, including:

  • Low sensor latency
    Total end-to-end latency from the IMU, accelerometer,and gyro to an application-visible callback must be extremely low (<5ms typically). This is required for HIFI sensor support.
  • Low display latency
    Total end-to-end latency from the GPU draw calls to the actual display update must be as low as possible. This is achieved by using SurfaceFlinger in a single-buffered mode, and assuring that draw calls are synchronized with the display scanout correctly. This behavior is exposed via an EGL extension to applications. See below for the EGL extensions needed for this.
  • Low-persistence display
    Display persistence settings must be set as low as possible while still maintaining a reasonable brightness. For a typical display running at 60Hz, pixels should be illuminated for <=3.5ms to be considered low-persistence. This avoids ghosting during movements in a VR setting, and should be enabled from the lights.h HAL when BRIGHTNESS_MODE_LOW_PERSISTENCE is set.
  • Consistent performance of the GPU and CPU
    When given a mixed GPU/CPU workload for a VR application with bursts of work at regular intervals several times a frame, the CPU scheduling should ensure that the application render thread work is run consistently within 1ms of when scheduled, and completed before the end of the draw window. To this end, a single CPU core must be reserved for solely for the currently running VR application's render thread while in VR mode, and made available in the "top-app" cpuset. Likewise, an appropriate CPU, GPU, and bus clockrate must be maintained to ensure that the rendering workload finishes within the time allotted to render each frame when the POWER_HINT_SUSTAINED_PERFORMANCE flag has been set in the power.h HAL while in VR mode when the device is not being thermally throttled.
  • Required EGL extensions must be present
    Any GPU settings required to allow the above capabilities are required, including the EGL extensions:
    EGL_ANDROID_create_native_client_buffer, EGL_ANDROID_front_buffer_auto_refresh,
    EGL_EXT_protected_content, EGL_KHR_mutable_render_buffer,
    EGL_KHR_reusable_sync, and EGL_KHR_wait_sync.
  • Accurate thermal reporting
    Accurate thermal temperatures and limits must be reported in the thermal.h HAL. Specifically, the current skin temperature must accurately be reported for DEVICE_TEMPERATURE_SKIN and the vr_throttling_threshold reported for this device must accurately report the temperature limit above which the device's thermal governor throttles the CPU, GPU, and/or bus clockrates below the minimum necessary for consistent performance (see previous bullet point).

In general, vendors implementing this HAL are expected to use set_vr_mode as a hint to enable VR-specific performance tuning needed for any of the above requirements, and to turn on any device features optimal for VR display modes. The set_vr_mode call may simply do nothing if no optimizations are available or necessary to meet the above requirements.
No methods in this HAL will be called concurrently from the Android framework.

 typedef struct vr_module {
    /**
     * Common methods of the  module.  This *must* be the first member of
     * vr_module as users of this structure may cast a hw_module_t to a
     * vr_module pointer in contexts where it's known that the hw_module_t
     * references a vr_module.
     */
    struct hw_module_t common;
    /**
     * Convenience method for the HAL implementation to set up any state 
     * needed
     * at runtime startup.  This is called once from the VrManagerService 
     * during
     * its boot phase.  No methods from this HAL will be called before init.
     */
    void (*init)(struct vr_module *module);

    /**
     * Set the VR mode state.  Possible states of the enabled parameter 
     * are:
     * false - VR mode is disabled, turn off all VR-specific settings.
     * true - VR mode is enabled, turn on all VR-specific settings.
     * This is called whenever the the Android system enters or leaves VR 
     * mode.
     * This will typically occur when the user switches to or from a VR 
     * application
     * that is doing stereoscopic rendering.
     */
    void (*set_vr_mode)(struct vr_module *module, bool enabled);
    /* Reserved for future use. Must be NULL. */
    void* reserved[8 - 2];
} vr_module_t;  

这个HAL层的实现是可选择的,毕竟不是每个Android N的手机都必须要支持DayDream平台。
VrManagerService是一个系统级别的服务,它的主要作用描述如下:

  • Service tracking whether VR mode is active, and notifying listening services of state changes.
  • Services running in system server may modify the state of VrManagerService via the interface in VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the interface given in VrStateListener.
  • Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.: hardware/libhardware/modules/vr
  • In general applications may enable or disable VR mode by calling android.app.Activity.setVrModeEnabled An application may also implement a service to be run while in VR mode by implementing android.service.vr.VrListenerService.

从描述来看,它是一个vr模式的控制中心,system_server里面的其他服务除了可以通过VrManagerInternal这个接口去控制vr模式,还可以通过VrStateListener接口注册一些vr状态变化的通知,它也是通过底层的vr HAL层去实际打开VR模式的。在system_server进程里面可以通过如下两种方式来访问到这个服务:

  • 通过binder查找服务的方式:
IVrManager vrManager = IVrManager.Stub.asInterface( ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
 if (vrManager != null) {
      try {
          vrManager.registerListener(mVrStateCallbacks);
          mVrModeEnabled = vrManager.getVrModeState();
      } catch (RemoteException re) {
      }
  }
  • System_server进程内部通过localservice的方式:
    mVrManagerInternal = getLocalService(VrManagerInternal.class);

在Android N上面Activity提供了一个新的接口setVrModeEnabled,这个函数会通过binder调用AMS的setVrmode接口,而在AMS的setVrmode最终调用的是VrManagerService的setVrmode函数,VrManagerService又是通过vr HAL层去打开这个VR模式,通过这样的一个调用链,使手机进入VR模式。

//enabled:true进入VR模式,false退出VR模式.
//requestedComponent 指定一个继承android.service.vr.VrListenerService 的服务,这个服务由VrManagerService来调用,如果没有指定,不会进入VR模式.
public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)throws PackageManager.NameNotFoundException {
     try {
            if (ActivityManagerNative.getDefault().setVrMode(mToken, 
                enabled, requestedComponent)!= 0) {
                throw new PackageManager.NameNotFoundException(
                        requestedComponent.flattenToString());
            }
     } catch (RemoteException e) {
            // pass
     }
}

上面说过system_server进程里面的其他服务和其他进程可以通过VrStateListener的接口获知当前的VR模式变化信息,搜索了一下目前系统里面实现了VrStateListener接口的有以下几处代码:

Android N 实现了VrStateListener的地方

VR之所以被人喜欢,是因为能获得一种沉浸式体验,所以在VR模式下,人们是不喜欢被其他事情打扰的,PowerManagerService、BaseStatusBar等服务监听VR模式的变化就可以相应的改变逻辑行为,比如不显示通知信息等。

VrManagerService的另外一个重要功能是监听设置里面关于VR模式的开关状态,在VrManagerService.java的文件夹目录下面还有一个EnabledComponentsObserver,它继承了SettingChangeListener,所以可以获取设置中关于VR的开关状态变化,VrManagerService是在onBootPhase这个函数里面把自己加入到EnabledComponentsObserver的监控列表里面去的,以后只要开关状态有变化,那么VrManagerService就能获取到通知了。

@Override
public void onBootPhase(int phase) {
    if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
        synchronized (mLock) {
            Looper looper = Looper.getMainLooper();
            Handler handler = new Handler(looper);
            ArrayList<EnabledComponentChangeListener> listeners = new 
            ArrayList<>();
            listeners.add(this);
            mComponentObserver =  
               EnabledComponentsObserver.build(mContext, handler,
                   Settings.Secure.ENABLED_VR_LISTENERS, looper,
                   android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
                   VrListenerService.SERVICE_INTERFACE, mLock, 
                   listeners);
                mComponentObserver.rebuildAll();
         }
     }
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容