Android Vsync 原理淺析

来源:https://www.cnblogs.com/frrj/archive/2018/07/30/brief-info-of-android-display.html
-Advertisement-
Play Games

Preface Android中,Client測量和計算佈局,SurfaceFlienger(server)用來渲染繪製界面,client和server的是通過匿名共用記憶體(SharedClient)通信。 每個應用和SurfaceFlienger之間都會創建一個SharedClient,一個Sha ...


Preface

Android中,Client測量和計算佈局,SurfaceFlienger(server)用來渲染繪製界面,client和server的是通過匿名共用記憶體(SharedClient)通信。

每個應用和SurfaceFlienger之間都會創建一個SharedClient,一個SharedClient最多可以創建31個SharedBufferStack,每個surface對應一個SharedBufferStack,也就是一個Window。也就意味著,每個應用最多可以創建31個視窗。


Android 4.1 之後,AndroidOS 團隊對Android Display進行了不斷地進化和改變。引入了三個核心元素:Vsync,Triple Butter,Choreographer。

首先來理解一下,圖形界面的繪製,大概是有CPU準備數據,然後通過驅動層把數據交給GPU來進行繪製。圖形API不允許CPU和GPU直接通信,所以就有了圖形驅動(Graphics Driver)來進行聯繫。Graphics Driver維護了一個序列(Display List),CPU不斷把需要顯示的數據放進去,GPU不斷取出來進行顯示。

其中Choreographer起調度的作用。統一繪製圖像到Vsync的某個時間點。

Choreographer在收到Vsync信號時,調用用戶設置的回調函數。函數的先後順序如下:

CALLBACK_INPUT:與輸入事件有關
CALLBACK_ANIMATION:與動畫有關
CALLBACK_TRAVERSAL:與UI繪製有關

Vsync是什麼呢?首先來說一下什麼是FPS,FPS就是Frame Per Second(每秒的幀數)的縮寫,我們知道,FPS>=60時,我們就不會覺得動畫卡頓。當FPS=60時是個什麼概念呢?1000/60≈16.6,也就是說在大概16ms中,我們要進行一次屏幕的刷新繪製。Vsync是垂直同步的縮寫。這裡我們可以簡單的理解成,這就是一個時間中斷。例如,每16ms會有一個Vsync信號,那麼系統在每次拿到Vsync信號時刷新屏幕,我們就不會覺得卡頓了。

但實現起來還是有點困難的。


多重緩衝是什麼技術呢?我們先來說雙重緩衝。在Linux上,通常使用FrameBuffer來做顯示輸出。雙重緩衝會創建一個FrontBuffer和一個BackBuffer,顧名思義,FrontBuffer是當前顯示的頁面,BackBuffer是下一個要顯示的畫面。然後滾動電梯式顯示數據。為什麼呢?這樣好在哪裡呢?首先他並不是不卡了,他還是會卡。但是如果是單重緩衝,頁面可能會有這種情況:A面數據需要顯示,然後是B面數據顯示,B面數據顯示需要耗費一定時間,但是這個時間里,C面數據也請求了展示,我們可能會看到,在展示C面數據的時候,還有B面數據的殘影…

下麵分情況來具體說明一下(Vsync每16秒一次)。

1.沒有使用Vsync的情況

可以看出,在第一個16ms之內,一切正常。然而在第二個16ms之內,幾乎是在時間段的最後CPU才計算出了數據,交給了Graphics Driver,導致GPU也是在第二段的末尾時間才進行了繪製,整個動作延後到了第三段內。從而影響了下一個畫面的繪製。這時會出現Jank(閃爍,可以理解為卡頓或者停頓)。那麼在第二個16ms前半段的時間CPU和GPU乾什麼了?哦,他們可能忙別的事情了。這就是卡頓出現的原因和情況。CPU和GPU很隨意,愛什麼時候刷新什麼時候刷新,很隨意。

2.有Vsync的情況

如果,按照之前的前提來說,Vsync每16ms一次,那麼在每次發出Vsync命令時,CPU都會進行刷新的操作。也就是在每個16ms的第一時間,CPU就會想贏Vsync的命令,來進行數據刷新的動作。CPU和GPU的刷新時間,和Display的FPS是一致的。因為只有到發出Vsync命令的時候,CPU和GPU才會進行刷新或顯示的動作。圖中是正常情況。那麼不正常情況是怎麼個情況?我們先來說一下雙重緩衝,然後再說。

3.雙重緩衝

邏輯就是和之前一樣。多重緩衝頁面在Back Buffer,然後根據需求來顯示不同數據。但是會有什麼問題呢(這就是2中提到的問題)?

首先我們看Display行,A頁面需要了兩個時間單位,為什麼?因為B Buffer在處理的時候太耗時了。然後導致了,在第一個Vsync發出的時候,還在GPU還在繪製B Buffer。那麼,剛好,第一個Vsync發出之後很短的時間,A頁面展示完了,B Buffer的也在一開始的時候就不進行計算了。那麼接下來的時間呢?屏幕還是展示著B Buffer,這時候就會造成Jank現象。他不會動,因為他在等下一個Vsync過來的時候,才會顯示下一個數據。

那麼,如圖,在A Buffer過來的時候,展示B頁面的數據。這個時候!重覆了上一個情況,也是太耗時了,然後又覆蓋了下一個Vysnc發
出的時間,再次造成卡頓!依次類推,會造成多次卡頓。這個時候就有了三重緩衝的概念。

4.三重緩衝

首先看圖。我們看到,B Buffer依舊很耗時,同樣覆蓋了第一個Vsync發出的時間點。但是,在第一個Vsync發出的時候,C Buffer站了出來,說,我來展示這個頁面,你去緩衝A後面需要緩衝的頁面吧!然後會發生什麼?然後就是出現了一個Jank…,但是這個Jank只在這一個時間單位出現,是可以忽略不計的。因為之後的邏輯都是順暢的了。依次類推,除了A和B 兩個圖層在交替顯示,還有個“第三者”在不斷幫他們兩個可能需要展示的數據進行緩衝。但是註意了:

只有在需要時,才會進行三重緩衝。正常情況下,只使用二級緩衝!

另外,緩衝區不是越多越好。上圖,C頁面在第四個時間段才展示出來,就是因為中間多了一個Buffer(C Buffer)來進行緩衝。

但是,雖然谷歌給了你這麼牛逼的前提邏輯,實際開發中你寫的APP還是會卡,為什麼呢?原因大概有兩點:

1.界面太複雜。

2.主線程(UI線程)太忙。他可能還在處理用戶交互或者其他事情。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 打開firewalld防火牆 2. 添加防火牆規則(對指定ip開放指定埠) (以下紅色字體需要根據實際情況修改) (1) Postgresql埠設置。允許192.168.142.166訪問5432埠 (2)redis埠設置。允許192.168.142.166訪問6379埠 (3)be ...
  • 出現這個問題是因為yum在安裝包的過程中,雖然已經聯網,但是沒法解析遠程包管理庫對應的功能變數名稱,所以我們只需要在網路配置中添加上DNS對應的ip地址即可。 解決參考鏈接:https://blog.csdn.net/qq_23212697/article/details/69305822 再次執行命令: ...
  • 打一個比較形象的比喻,把APP比作我們的人體,把胳膊、大腿、心、肝、肺這些人體器官比作組件,各個器官分別負責他們各自的功能,但是他們之間也有主次之分,試想我們的胳膊、大腿等是不能獨立完成某個任務的,必須需要心、肺、肝、膽等的能量支持,那麼可以把胳膊、大腿這種功能性器官比作業務組件,把我們的心、肝、脾 ...
  • 女孩:BroadcastReceiver是什麼呀? 男孩:Broadcast是廣播的意思,在Android中應用程式之間的傳輸信息的機制,BroadcastReceiver是接收廣播通知的組件,廣播和廣播接收器是Android中需要瞭解的,那麼怎麼樣去瞭解呢~ 廣播,大家應該可以理解,我們在學校做眼 ...
  • 1.使用 工具欄 -> Analyze -> Inspect Code… 點擊 Inspect Code 後會彈出檢查範圍的對話框: 預設是檢查整個項目,我們可以點擊 Custom scope 自定義檢查範圍。 點擊右邊的下拉框,會出現以下選擇: 分別有: Project Files:所有項目文件 ...
  • 安裝APK 發送請求獲取輸入流 解析XML文件 可以開始下載 跟蹤下載進度 下載完畢啟動安裝 獲取項目包名 ...
  • 系統路徑 文件操作 資源文件assets和RW res/raw:文件會被映射到R.java文件中,訪問的時候直接通過資源ID訪問,沒有有目錄結構 assets:不會映射到R.java文件中,通過AssetManager來訪問,能有目錄結構 從資源文件中獲取Bitmap ...
  • ios的viewcontroller生命周期是 init -> loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear -> viewWillDisappear -> viewDidAppear -> viewDidUnload -> d ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...