雖然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接口的有以下幾處代碼:
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();
}
}
}