日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作為一款VR實時操作游戲App,我們需要根據(jù)重力感應系統(tǒng),實時監(jiān)控手機的角度,并渲染出相應位置的VR圖像,因此在不同 Android 設備之間,由于使用的芯片組和不同架構(gòu)的GPU,游戲性能會因此受到影響。舉例來說:游戲在 Galaxy S20+ 上可能以 60fps 的速度渲染,但它在HUAWEI P50 Pro上的表現(xiàn)可能與前者大相徑庭。 由于新版本的手機具有良好的配置,而游戲需要考慮基于底層硬件的運行情況。

如果玩家遇到幀速率下降或加載時間變慢,他們很快就會對游戲失去興趣。如果游戲耗盡電池電量或設備過熱,我們也會流失處于長途旅行中的游戲玩家。如果提前預渲染不必要的游戲素材,會大大增加游戲的啟動時間,導致玩家失去耐心。如果幀率和手機不能適配,在運行時會由于手機自我保護機制造成閃退,帶來極差的游戲體驗。

基于此,我們需要對代碼進行優(yōu)化以適配市場上不同手機的不同幀率運行。

所遇到的挑戰(zhàn)

首先我們使用Streamline 獲取在 Android 設備上運行的游戲的配置文件,在運行測試場景時將 CPU 和 GPU性能計數(shù)器活動可視化,以準確了解設備處理 CPU 和 GPU 工作負載,從而去定位幀速率下降的主要問題。

以下的幀率分析圖表顯示了應用程序如何隨時間運行。

在下面的圖中,我們可以看到執(zhí)行引擎周期與 FPS 下降之間的相關(guān)性。顯然GPU 正忙于算術(shù)運算,并且著色器可能過于復雜。

為了測試在不同設備中的幀率情況,使用友盟+U-APM測試不同機型上的卡頓狀況,發(fā)現(xiàn)在onSurfaceCreated函數(shù)中進行渲染時出現(xiàn)卡頓, 應證了前文的分析,可以確定GPU是在算數(shù)運算過程中發(fā)生了卡頓:

因為不同設備有不同的性能預期,所以需要為每個設備設置自己的性能預算。例如,已知設備中 GPU 的最高頻率,并且提供目標幀速率,則可以計算每幀 GPU 成本的絕對限制。

數(shù)學公式: $ 每幀 GPU 成本 = GPU 最高頻率 / 目標幀率 $

CPU 到 GPU 的調(diào)度存在一定的約束,由于調(diào)度上存在限制所以我們無法達到目標幀率。另外,由于 CPU-GPU 接口上的工作負載序列化,渲染過程是異步進行的。CPU 將新的渲染工作放入隊列,稍后由 GPU 處理。

數(shù)據(jù)資源問題

CPU 控制渲染過程并且實時提供最新的數(shù)據(jù),例如每一幀的變換和燈光位置。然而,GPU 處理是異步的。這意味著數(shù)據(jù)資源會被排隊的命令引用,并在命令流中停留一段時間。而程序中的OpenGL ES 需要渲染以反映進行繪制調(diào)用時資源的狀態(tài),因此在引用它們的 GPU 工作負載完成之前無法修改資源。

調(diào)試過程

我們曾做出嘗試,對引用資源進行代碼上的編輯優(yōu)化,然而當我們嘗試修改這部分內(nèi)容時,會觸發(fā)該部分的新副本的創(chuàng)建。這將能夠一定程度上實現(xiàn)我們的目標,但是會產(chǎn)生大量的 CPU 開銷。

于是我們使用Streamline查明高 CPU 負載的實例。在圖形驅(qū)動程序內(nèi)部libGLES_Mali.so路徑函數(shù), 視圖中看到極高的占用時間。

由于我們希望在不同手機上適配不同幀率運行,所以需要查明libGLES_Mali.so是否在不同機型的設備上都產(chǎn)生了極高的占用時間,此處采用了友盟+U-APM來檢測用戶在不同機型上的函數(shù)占用比例。

經(jīng)友盟+ U-APM自定義異常測試,下列機型會產(chǎn)生高libGLES_Mali.so占用的問題,因此我們需要基于底層硬件的運行情況來解決流暢性問題,同時由于存在問題的機型不止一種,我們需要從內(nèi)存層面著手,考慮如何調(diào)用較少的內(nèi)存緩存區(qū)并及時釋放內(nèi)存。

解決方案及優(yōu)化

基于前文的分析,我們首先嘗試從緩沖區(qū)入手進行優(yōu)化。單緩沖區(qū)方案• 使用glMapBufferRange和GL_MAP_UNSYNCHRONIZED.然后使用單個緩沖區(qū)內(nèi)的子區(qū)域構(gòu)建旋轉(zhuǎn)。這避免了對多個緩沖區(qū)的需求,但是這一方案仍然存在一些問題,我們?nèi)孕枰幚砉芾碜訁^(qū)域依賴項,這一部分的代碼給我們帶來了額外的工作量。多緩沖區(qū)方案• 我們嘗試在系統(tǒng)中創(chuàng)建多個緩沖區(qū),并以循環(huán)方式使用緩沖區(qū)。通過計算我們得到了適合的緩沖區(qū)的數(shù)目,在之后的幀中,代碼可以去重新使用這些循環(huán)緩沖區(qū)。由于我們使用了大量的循環(huán)緩沖區(qū),那么大量的日志記錄和數(shù)據(jù)庫寫入是非常有必要的。但是有幾個因素會導致此處的性能不佳:1. 產(chǎn)生了額外的內(nèi)存使用和GC壓力2. Android 操作系統(tǒng)實際上是將日志消息寫入日志而并非文件,這需要額外的時間。3. 如果只有一次調(diào)用,那么這里的性能消耗微乎其微。但是由于使用了循環(huán)緩沖區(qū),所以這里需要用到多次調(diào)用。我們會在基于c#中的 Mono 分析器中啟用內(nèi)存分配跟蹤函數(shù)用于定位問題:

$ adb shell setprop debug.mono.profile log:calls,alloc

我們可以看到該方法在每次調(diào)用時都花費時間:

Method call summary Total(ms) Self(ms) Calls Method name 782 5 100 MyApp.MainActivity:Log (string,object[]) 775 3 100 Android.Util.Log:Debug (string,string,object[]) 634 10 100 Android.Util.Log:Debug (string,string)

在這里定位到我們的日志記錄花費了大量時間,我們的下一步方向可能需要改進單個調(diào)用,或者尋求全新的解決方案。

log:alloc還讓我們看到內(nèi)存分配;日志調(diào)用直接導致了大量的不合理內(nèi)存分配:

Allocation summary Bytes Count Average Type name 41784 839 49 System.String 4280 144 29 System.Object[]

硬件加速

最后嘗試引入硬件加速,獲得了一個新的繪圖模型來將應用程序渲染到屏幕上。它引入了 DisplayList 結(jié)構(gòu)并且記錄視圖的繪圖命令以加快渲染速度。

同時,可以將 View 渲染到屏幕外緩沖區(qū)并隨心所欲地修改它而不用擔心被引用的問題。此功能主要適用于動畫,非常適合解決我們的幀率問題,可以更快地為復雜的視圖設置動畫。

如果沒有圖層,在更改動畫屬性后,動畫視圖將使其無效。對于復雜的視圖,這種失效會傳播到所有的子視圖,它們反過來會重繪自己。

在使用由硬件支持的視圖層后,GPU 會為視圖創(chuàng)建紋理。因此我們可以在我們的屏幕上為復雜的視圖設置動畫,并且使動畫更加流暢。

代碼示例:

// Using the Object animator view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 20f); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); objectAnimator.start(); // Using the Property animator view.animate().translationX(20f).withLayer().start();

另外還有幾點在使用硬件層中仍需注意:

(1)在使用之后進行清理:

硬件層會占用GPU上的空間。在上面的 ObjectAnimator代碼中,偵聽器會在動畫結(jié)束時移除圖層。在 Property animator 示例中,withLayers() 方法會在開始時自動創(chuàng)建圖層并在動畫結(jié)束時將其刪除。

(2)需要將硬件層更新可視化:

使用開發(fā)人員選項,可以啟用“顯示硬件層更新”。如果在應用硬件層后更改視圖,它將使硬件層無效并將視圖重新渲染到該屏幕外緩沖區(qū)。

硬件加速優(yōu)化

但是由此帶來了一個問題是,在不需要快速渲染的界面,比如滾動欄, 硬件層也會更快地渲染它們。當將 ViewPager 滾動到兩側(cè)時,它的頁面在整個滾動階段會以綠色突出顯示。

因此當我滾動 ViewPager 時,我使用 DDMS 運行 TraceView,按名稱對方法調(diào)用進行排序,搜索“android/view/View.setLayerType”,然后跟蹤它的引用:

ViewPager#enableLayers(): private void enableLayers(boolean enable) { final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final int layerType = enable ? ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; ViewCompat.setLayerType(getChildAt(i), layerType, null); } }

該方法負責為 ViewPager 的孩子啟用/禁用硬件層。它從 ViewPaper#setScrollState() 調(diào)用一次:

private void setScrollState(int newState) { if (mScrollState == newState) { return; } mScrollState = newState; if (mPageTransformer != null) { enableLayers(newState != SCROLL_STATE_IDLE); } if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageScrollStateChanged(newState); } }

正如代碼中所示,當滾動狀態(tài)為 IDLE 時硬件被禁用,否則在 DRAGGING 或 SETTLING 時啟用。PageTransformer 旨在“使用動畫屬性將自定義轉(zhuǎn)換應用于頁面視圖”(Source)。

基于我們的需求,只在渲染動畫的時候啟用硬件層,所以我想覆蓋ViewPager 方法,但由于它們是私有的,我們無法修改這個方法。

所以我采取了另外的解決方案:在 ViewPage#setScrollState() 上,在調(diào)用 enableLayers() 之后,我們還會調(diào)用 OnPageChangeListener#onPageScrollStateChanged()。所以我設置了一個監(jiān)聽器,當 ViewPager 的滾動狀態(tài)不同于 IDLE 時,它將所有 ViewPager 的孩子的圖層類型重置為 NONE:

@Override public void onPageScrollStateChanged(int scrollState) { // A small hack to remove the HW layer that the viewpager add to each page when scrolling. if (scrollState != ViewPager.SCROLL_STATE_IDLE) { final int childCount = <your_viewpager>.getChildCount(); for (int i = 0; i < childCount; i++) <your_viewpager>.getChildAt(i).setLayerType(View.LAYER_TYPE_NONE, null); } }

這樣,在 ViewPager#setScrollState() 為頁面設置了一個硬件層之后——我將它們重新設置為 NONE,這將禁用硬件層,因此而導致的幀率區(qū)別主要顯示在 Nexus上。

分享到:
標簽:借助 流暢 加速 優(yōu)化 硬件 系統(tǒng) 游戲 GPU
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定