Android N VR代碼簡析

雖然Google早在2016的IO大會上就說DayDream會隨著Android N發(fā)布,但是從Android N的前幾個版本的代碼來看蔫劣,都是沒有集成的坪郭,直到Android-7.0.0_r14這個版本,才可以看到DayDream的一些簡單代碼脉幢,跟之前預(yù)見的一樣歪沃,DayDream跟三星的GearVR采用的是同樣的架構(gòu),都分離出來一個單獨的VR SDK嫌松,比如三星的Oculus SDK沪曙,Google的Google VR SDK,應(yīng)用基于他們的SDK開發(fā)應(yīng)用程序萎羔,然后運行在支持這些SDK的Android系統(tǒng)上面液走。

單獨分離出一個SDK,除了方便應(yīng)用開發(fā)者之外贾陷,主要的目的是用來把VR的一些核心算法隱藏起來缘眶,比如用來減少延遲的ATW異步時間扭曲算法就是被封裝在這里,是閉源不公開的髓废,眾所周知巷懈,在手機上面運行VR的時候一個最大的挑戰(zhàn)就是延遲,當一副畫面的延遲超過20MS瓦哎,人就會感覺不舒服惡心砸喻,嚴重影響用戶體驗柔逼,一個好的VR產(chǎn)品都會盡量避免延遲。目前在Mobile VR上主要有以下幾種方式來減少延遲:

1割岛、 硬件層面的優(yōu)化

  • 提升傳感器的采樣頻率,減少刷新率與傳感器頻率的同步等待時間消耗愉适。
  • 提升傳感器的精度, 減少對采樣數(shù)據(jù)進行穩(wěn)定性過濾產(chǎn)生的延遲。
  • 采用有線傳輸也有一部分原因是出于延遲的考慮癣漆。
  • 屏幕使用OLED替代LCD, 減少像素顏色切換的時間维咸。
  • 提升屏幕刷新率, 主流的屏幕是60Hz, 那每幀就是16.67ms; 如果提升到90Hz, 那每幀就是11.11ms.
  • 雙GPU渲染,一個GPU負責左眼的畫面惠爽,一個GPU負責右眼的渲染癌蓖。

2、 軟件層面的優(yōu)化

  • 多分辨率渲染婚肆,VR畫面的中心部分可以高分辨率渲染租副,周邊部分低分辨率渲染
  • 上面提過的ATW算法,一個具有高優(yōu)先級的線程较性,以一定的幀率用僧,不斷的根據(jù)Android渲染出來的畫面生
    成一個新的畫面,然后投遞到屏幕赞咙。
  • Front Buffer Render责循,即只有一個render buffer,應(yīng)用趕在下一個屏幕刷新周期到來之前把畫面更新到這個render buffer攀操,然后屏幕使用這個render buffer更新顯示內(nèi)容院仿,這個需要修改GPU和Display的Driver部分代碼。

Android N的DayDream對硬件和軟件的一些需求速和,其實都是根據(jù)上面這些優(yōu)化手段提出來的歹垫,具體到Android N的代碼來說,它提供了一個SDK健芭,應(yīng)該是解決了ATW算法和多分辨率渲染等優(yōu)化問題县钥,然后新增了一個系統(tǒng)服務(wù)VrManagerService和 vr HAL層, 應(yīng)用通過VrManagerService來設(shè)置系統(tǒng)進入VR模式慈迈,VrManagerService又是通過vr HAL層去實現(xiàn)具體模式的切換的若贮。

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層的實現(xiàn)是可選擇的,畢竟不是每個Android N的手機都必須要支持DayDream平臺痒留。
VrManagerService是一個系統(tǒng)級別的服務(wù)谴麦,它的主要作用描述如下:

  • 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里面的其他服務(wù)除了可以通過VrManagerInternal這個接口去控制vr模式匾效,還可以通過VrStateListener接口注冊一些vr狀態(tài)變化的通知,它也是通過底層的vr HAL層去實際打開VR模式的恤磷。在system_server進程里面可以通過如下兩種方式來訪問到這個服務(wù):

  • 通過binder查找服務(wù)的方式:
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進程內(nèi)部通過localservice的方式:
    mVrManagerInternal = getLocalService(VrManagerInternal.class);

在Android N上面Activity提供了一個新的接口setVrModeEnabled,這個函數(shù)會通過binder調(diào)用AMS的setVrmode接口面哼,而在AMS的setVrmode最終調(diào)用的是VrManagerService的setVrmode函數(shù)野宜,VrManagerService又是通過vr HAL層去打開這個VR模式,通過這樣的一個調(diào)用鏈魔策,使手機進入VR模式匈子。

//enabled:true進入VR模式,false退出VR模式.
//requestedComponent 指定一個繼承android.service.vr.VrListenerService 的服務(wù),這個服務(wù)由VrManagerService來調(diào)用闯袒,如果沒有指定虎敦,不會進入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進程里面的其他服務(wù)和其他進程可以通過VrStateListener的接口獲知當前的VR模式變化信息,搜索了一下目前系統(tǒng)里面實現(xiàn)了VrStateListener接口的有以下幾處代碼:

Android N 實現(xiàn)了VrStateListener的地方

VR之所以被人喜歡政敢,是因為能獲得一種沉浸式體驗其徙,所以在VR模式下,人們是不喜歡被其他事情打擾的喷户,PowerManagerService唾那、BaseStatusBar等服務(wù)監(jiān)聽VR模式的變化就可以相應(yīng)的改變邏輯行為,比如不顯示通知信息等褪尝。

VrManagerService的另外一個重要功能是監(jiān)聽設(shè)置里面關(guān)于VR模式的開關(guān)狀態(tài)通贞,在VrManagerService.java的文件夾目錄下面還有一個EnabledComponentsObserver,它繼承了SettingChangeListener恼五,所以可以獲取設(shè)置中關(guān)于VR的開關(guān)狀態(tài)變化,VrManagerService是在onBootPhase這個函數(shù)里面把自己加入到EnabledComponentsObserver的監(jiān)控列表里面去的哭懈,以后只要開關(guān)狀態(tài)有變化灾馒,那么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();
         }
     }
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遣总,一起剝皮案震驚了整個濱河市睬罗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旭斥,老刑警劉巖容达,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異垂券,居然都是意外死亡花盐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門菇爪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來算芯,“玉大人,你說我怎么就攤上這事凳宙∥踝幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵氏涩,是天一觀的道長届囚。 經(jīng)常有香客問我有梆,道長淘正,這世上最難降的妖魔是什么珍手? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任悬襟,我火速辦了婚禮端仰,結(jié)果婚禮上窿侈,老公的妹妹穿的比我還像新娘扼雏。我一直安慰自己屿岂,他們只是感情好坞琴,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布作郭。 她就那樣靜靜地躺著陨囊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夹攒。 梳的紋絲不亂的頭發(fā)上蜘醋,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音咏尝,去河邊找鬼压语。 笑死,一個胖子當著我的面吹牛编检,可吹牛的內(nèi)容都是我干的胎食。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼允懂,長吁一口氣:“原來是場噩夢啊……” “哼厕怜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蕾总,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤粥航,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后生百,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體递雀,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年蚀浆,在試婚紗的時候發(fā)現(xiàn)自己被綠了缀程。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜡坊,死狀恐怖杠输,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秕衙,我是刑警寧澤蠢甲,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站据忘,受9級特大地震影響鹦牛,放射性物質(zhì)發(fā)生泄漏搞糕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一曼追、第九天 我趴在偏房一處隱蔽的房頂上張望窍仰。 院中可真熱鬧,春花似錦礼殊、人聲如沸驹吮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碟狞。三九已至,卻和暖如春婚陪,著一層夾襖步出監(jiān)牢的瞬間族沃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工泌参, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脆淹,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓沽一,卻偏偏與公主長得像盖溺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铣缠,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容