Android GPU渲染SurfaceFlinger合成RenderThread的dequeueBuffer/queueBuffer與fence機制(2)

Android GPU渲染SurfaceFlinger合成RenderThread的dequeueBuffer/queueBuffer與fence機制(2)

?

計算fps幀率

adb shell dumpsys SurfaceFlinger --list

查詢當前的SurfaceView,然后有好多行,再把要查詢的行內容完整的傳給

adb shell dumpsys SurfaceFlinger --latency 窗口名

輸出一堆數字,第一行數字是當前的 VSYNC 間隔,單位納秒。如果屏幕是 60Hz ,就是 16.6ms,然后下面一堆數字,總共有 127 行,每一行有 3 個數字,每個數字都是時間戳,單位是納秒。

Android 顯示一幀大致分為幾個步驟
1,App 接收到 vsync-app 信號后開始工作。
2,App 主線程被Message喚醒,執行onVsync。
3,App 執行 doFrame ,處理input、animation、traversal、draw等。
4,App UIThread 跟RenderThread sync 數據。
5,App 執行DrawFrame,從SurfaceFlinger(后續簡稱SF) 的 BufferQueue 中 dequeueBuffer,取出一個bufffer后,執行渲染繪制,接著將繪制好的Buffer 通過queueBuffer 放回到BufferQueue中給 SF消費。
6,App queueBuffer 后, SF 中對應的 app buffer 會增加 +1。
7,Vsync-sf 到來后,SF 從BufferQueue 中 acquireBuffer一個Buffer 進行消費, 對應SF 中的 app buffer 會減 - 1 , SF 消費處理后,通過 releaseBuffer 將buffer 歸還到BufferQueue 中。
8,SF 通過 bind 跟 Hardware Composer HAL(HWC) 進行通信,通過一些處理后顯示到手機屏幕上。

d48e7b7a06d948899b32b527b87c66e7.webp

dequeue(生產者發起) :
當生產者需要緩沖區時,它會通過調用 dequeueBuffer() 從 BufferQueue 請求一個可用的緩沖區,并指定緩沖區的寬度、高度、像素格式和使用標記。
queue(生產者發起):
生產者填充緩沖區并通過調用 queueBuffer() 將緩沖區返回到隊列。
acquire(消費者發起) :
消費者通過 acquireBuffer() 獲取該緩沖區并使用該緩沖區的內容。
release(消費者發起) :
當消費者操作完成后,它會通過調用 releaseBuffer() 將該緩沖區返回到隊列。

b1693a8c24824eaf8e54b84d84dba931.png
?

App 繪制的圖像內容是怎么最終顯示到手機屏幕?

App 要顯示的內容要繪制在 Buffer 里,這個 Buffer 是從 BufferQueue 通過 dequeueBuffer() 申請。申請到 Buffer 后,App 將內容填充到 Buffer ,通過 queueBuffer() 將 Buffer 還回去交給 SurfaceFlinger 去進行合成和顯示。然后,SurfaceFlinger 開始合成時候,調用 acquireBuffer() 從 BufferQueue 里面拿一個 Buffer 合成,合成完以后通過 releaseBuffer() 將 Buffer 還給 BufferQueue。

a388fd254642416d8af4e726c88f3678.webp

RenderThread 的 dequeueBuffer
dequeue 出隊,dequeueBuffer 就是從隊列中拿出一個 Buffer,這個隊列就是 SurfaceFlinger 中的 BufferQueue。app開始渲染前,首先需要通過 Binder 調用從 SurfaceFlinger 的 BufferQueue 中獲取一個 Buffer。

a089a2ede3af44a8ba2924305633f5a3.jpeg

RenderThread 的 queueBuffer
queue 入隊,queueBuffer 是把?Buffer 放回到 BufferQueue,App 處理完 Buffer 后,會把這個 Buffer 通過 eglSwapBuffersWithDamageKHR -> queueBuffer ,將 Buffer 放回 BufferQueue。

759d4f6f2ef3460a924d9af08c02c9dd.jpeg

上面流程有一個問題,在 App 繪制完通過 queueBuffer() 將 Buffer 還回時候,此時僅僅只是 CPU 側完成,GPU 實際上有沒有真正完成,CPU并不知道。因此如果此時GPU拿這個 Buffer 去合成/顯示,就會有問題(Buffer 可能還沒有完全繪制完)。由于 CPU 和 GPU 是異步的,因此CPU在代碼里執行一系列繪圖函數調用后,看上去函數已經返回,實際上,具體什么時候被GPU真正執行完畢 CPU 不知道,除非阻塞等待這些命令完全執行完,但這樣會帶來嚴重的性能問題,因為這樣使得 CPU 和 GPU 的并行完全喪失,CPU 會在 GPU 完成之前一直處于空等狀態。因此,需要一種機制,在不需要對 Buffer 進行讀寫時候,大家各干各的;當需要對 Buffer 進行讀寫時候,CPU可以知道此時 Buffer 在 GPU 的狀態,必要時候等一下。

fence 是這樣的同步機制——“柵欄”,把東西攔住。fence 要攔住什么東西呢?就是?Buffer。Buffer 在整個繪制、合成、顯示過程中,一直在 CPU,GPU 和 HWC 之間傳遞,某一方要使用 Buffer 前,需要檢查之前的使用者是否已經移交?Buffer 的“使用權”。而這里的“使用權”,就是 fence。當 fence 釋放(即 signal)時候,說明 Buffer 的上一個使用者已經交出了使用權,對于 Buffer 進行操作是安全的。

Android 總共有三類 fence —— acquire fence,release fence 和 present fence。

?acquire fence
? ? App 將 Buffer 通過 queueBuffer() 還給 BufferQueue 的時候,此時該 Buffer 的 GPU 側其實未必完成,此時會帶上一個 fence,這個 fence 就是 acquire fence。當 SurfaceFlinger/ HWC 要讀取 Buffer 以進行合成操作的時候,需要等 acquire fence 釋放之后才行。
?release fence
? ? 當 App 通過 dequeueBuffer() 從 BufferQueue 申請 Buffer,要對 Buffer 進行繪制時候,需要保證 HWC 已經不再需要這個 Buffer 了,即需要等 release fence signal 才能對 Buffer 進行寫操作。
?present fence
? ? 當前幀成功顯示到屏幕的時候,present fence 就會 signal。

d80f0e75cf0e4332b213b47447829bd9.png

每一個buffer都一個Fence狀態,代表這塊buffer是否還在被上一個使用者使用完,并且在轉移時都會攜帶當前Fence的fd,然后可以調用Fence的wait或者waitForever查詢Fence狀態,如果還在使用則等待,否則就可以使用。Fence按作用大體分兩種:acquireFence和releaseFence。前者用于生產者通知消費者生產已完成,后者用于消費者通知生產者消費已完成。

Fence保證GraphicBuffer在App, GPU和HWC三者間流轉時數據讀寫同步(不同進程 or 不同硬件間同步)。
從 SurfaceFlinger 的角度來看,App 部分主要負責生產 SurfaceFlinger 合成所需要的 Surface。
App 與 SurfaceFlinger 的交互主要集中在三點
1 Vsync 信號的接收和處理
2 RenderThread 的 dequeueBuffer
3 RenderThread 的 queueBuffer

384e0ea30071463c943b7132e063a0e3.jpeg
?

從 dumpsys SurfaceFlinger --latency 獲取最新 127 幀的 present fence 的 signal time,當某幀 present fence 被 signal 時候,說明這一幀已經被顯示到屏幕上。因此,可以通過判斷1秒內有多少個 present fence signal ,反推出一秒內有多少幀被刷新(顯示)到屏幕上,從而計算出 fps。

統計一秒內?App 往屏幕刷了多少幀,在 Android 里,每一幀顯示到屏幕的標志是:present fence signal ,因此計算 App 的 fps 就可以轉換為:一秒內 App 的 Layer 有多少個有效 present fence signal 。

?

?

?

Android adb shell命令捕獲systemtrace_android 抓trace-CSDN博客文章瀏覽閱讀1.7k次,點贊2次,收藏5次。Android ADB調試真機設備Android ADB(Andorid Debug Bridge),是Android開發中有用的測試和調試工具。使用Android ADB調試設備,直接在Windows的dos命令窗口輸入命名adb即可,如圖:為什么執行adb命令后是這樣?Android ADB(Andorid Debug Bridge)調試真機設備_adb在線執行器_zhangphil的博客-CSDN博客。-t 時長,20s,20秒的trace文件。-o 保存文件路徑。_android 抓tracehttps://blog.csdn.net/zhangphil/article/details/131249820

Android GPU渲染屏幕繪制顯示基礎概念(1)-CSDN博客文章瀏覽閱讀696次,點贊20次,收藏12次。CPU返回后,會直接將GraphicBuffer提交給SurfaceFlinger,告訴SurfaceFlinger進行合成,但是這個時候GPU可能并未完成之前的圖像渲染,這時候就牽扯到一個同步,Android中,用的是Fence機制,SurfaceFlinger合成前會查詢Fence,如果GPU渲染沒有結束,則等待GPU渲染結束,GPU結束后,會通知SurfaceFlinger進行合成,SF合成后,提交顯示,最終完成圖像的渲染顯示。而對SF來說,只要有合成任務,它就得再去申請VSYNC-sf。https://blog.csdn.net/zhangphil/article/details/138585120Android性能:Double Buffer雙緩沖/Triple Buffer三緩沖丟幀Jank與無丟幀No Jank-CSDN博客文章瀏覽閱讀858次,點贊6次,收藏13次。Android ADB調試真機設備Android ADB(Andorid Debug Bridge),是Android開發中有用的測試和調試工具。使用Android ADB調試設備,直接在Windows的dos命令窗口輸入命名adb即可,如圖:為什么執行adb命令后是這樣?_android 抓trace。三Buffer輪轉情況下,基本不會有這種情況的發生,渲染線程一般在 dequeueBuffer 時,都可以順利拿到可用的 Buffer (如果 dequeueBuffer 本身耗時那就也會拉長時間)。https://blog.csdn.net/zhangphil/article/details/138213964

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/9791.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/9791.shtml
英文地址,請注明出處:http://en.pswp.cn/web/9791.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法訓練Day35 | ● 343. 整數拆分 ● 96.不同的二叉搜索樹

343. 整數拆分 class Solution { public:int integerBreak(int n) {vector<int> dp(n1, 0);dp[2] 1;for(int i3; i<n1; i){for(int j 1; j<i/2; j){dp[i] max(dp[i], max(j*(i-j), j*dp[i-j]));}}return dp[n];} };參考文章&#xff1a;代碼隨想錄-343. 整數拆分…

找不到msvcp140.dll無法執行代碼的原因分析及修復方法

當用戶在嘗試運行某些應用程序或游戲時&#xff0c;可能會遇到系統彈出錯誤提示&#xff0c;顯示“找不到msvcp140.dll無法執行代碼”這一錯誤信息&#xff0c;它會導致程序無法正常啟動。為了解決這個問題&#xff0c;我經過多次嘗試和總結&#xff0c;找到了以下五種解決方法…

hadoop啟動后沒有namenode,datanode等解決方法

之前用的是虛擬機&#xff0c;在虛擬機上安裝的hadoop&#xff0c;但是后來&#xff0c;電腦恢復出廠設置了&#xff0c;什么都重新開始。就在本地安裝 Linux 子系統。 但是&#xff0c;有時候start-dfs.sh后&#xff0c;jps出現錯誤。 像這種拒絕連接 解決辦法就是如下&…

我的創作紀念日1460天(4年)

機緣 作為一名技術愛好者&#xff0c;我最初成為創作者的初心源于對知識的渴望和對分享的熱情。在參與多個實戰項目的過程中&#xff0c;我積累了豐富的經驗&#xff0c;這些經驗不僅僅是代碼和解決方案&#xff0c;更多的是對問題本質的理解和解決問題的思維方式。我意識到&a…

題目----力扣--移除鏈表元素

題目 給你一個鏈表的頭節點 head 和一個整數 val &#xff0c;請你刪除鏈表中所有滿足 Node.val val 的節點&#xff0c;并返回 新的頭節點 。 示例 1&#xff1a; 輸入&#xff1a;head [1,2,6,3,4,5,6], val 6 輸出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 輸入&…

如何編譯不同目錄下的兩個文件

1.直接編譯 2.打包成動靜態庫進行鏈接

【智能優化算法】蜜獾優化算法(Honey Badger Algorithm,HBA)

蜜獾優化算法(Honey Badger Algorithm,HBA)是期刊“MATHEMATICS AND COMPUTERS IN SIMULATION”&#xff08;IF 3.6&#xff09;的2022年智能優化算法 01.引言 蜜獾優化算法(Honey Badger Algorithm,HBA)受蜜獾智能覓食行為的啟發&#xff0c;從數學上發展出一種求解優化問題的…

【AMBA Bus ACE 總線 9 -- Non-cache IO device】

請閱讀【AMBA Bus ACE 總線與Cache 專欄 】 歡迎學習:【嵌入式開發學習必備專欄】 文章目錄 ACE Non-cache IO device非緩存I/O的工作原理在ARM中配置非緩存I/O示例場景Non-cache IO device Cache 訪問ACE Non-cache IO device 在ARM架構中,ACE(AXI Coherency Extension,…

Flask 統一攔截器

import osfrom flask import Flask, request, sessionapp Flask(__name__) app.config[SECRET_KEY] os.urandom(24) # 生成24位的隨機數種子&#xff0c;用于產生SESSION IDapp.route(/article/<int:article_id>) def test(article_id):"""路由地址參數…

變量的細節

如何打印不同類型的整數常量 相似于我們需要去聲明類型 public class Var {public static void main(String[] args) {// 1就是int類型常量System.out.println(1);// 120后面加一個L(l)表示他是一個long型的整數System.out.println(120l);} }如何打印不同類型的浮點數常量 與…

解決電腦睡眠后,主機ping不通VMware虛擬機

文章目錄 問題解決方法方法一方法二注意 問題 原因&#xff1a;電腦休眠一段時間&#xff0c;再次打開電腦就ping不通VMware虛擬機。 解決方法 方法一 重啟電腦即可&#xff0c;凡是遇到電腦有毛病&#xff0c;重啟能解決90%問題。但是重啟電腦比較慢&#xff0c;而且重啟…

C++用類模板封裝容器

要實現輸出不同容器的值&#xff0c;且各容器包含的數據類型也不同&#xff0c;可以使用類模板和函數模板來實現。 示例代碼如下&#xff1a; #include <iostream> #include <vector> #include <list>template <typename T> class Container { privat…

算法訓練Day36 | ● 01背包問題 ● 416. 分割等和子集

01背包問題 #include<iostream> #include<vector> using namespace std;int main(){int M;int N;cin>>M>>N;vector<int> weight(M, 0);vector<int> value(M, 0);for(int i0; i<M; i){cin>>weight[i];}for(int i0; i<M; i){ci…

Web3工具集合 - 00

使用 React 和 Material-UI 構建的 Web3 工具集合 大家好&#xff01; 我很高興向大家介紹我最近剛啟動了一個項目&#xff1a;Web3 工具集合。 這個項目的目的是一個集成各種 Web3 工具的網站&#xff0c;旨在為開發人員和加密貨幣愛好者提供便捷的工具和資源。 特點&#…

基于SSM的文化遺產的保護與旅游開發系統(有報告)。Javaee項目。ssm項目。

演示視頻&#xff1a; 基于SSM的文化遺產的保護與旅游開發系統&#xff08;有報告&#xff09;。Javaee項目。ssm項目。 項目介紹&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三層體系結構&#xff0c;…

基于ESP32和ESP8266的物聯網開發過程(二)

在做這個項目前&#xff0c;也做了一些調研。項目的初衷是想要用于智能家居。我比較了小米IoT、阿里云、ESPHOME、巴沙云、點燈科技和ONENET等幾個平臺。最終選擇了Onenet&#xff0c;部分原因是之前用過它的多協議版本&#xff0c;但現在這個版本已經下線了。 小米IoT的公測名…

C++ 類和對象:面向對象編程基礎

目錄標題 1. 什么是類&#xff1f;2. 什么是對象&#xff1f;3. 如何定義一個類&#xff1f;4. 如何創建對象&#xff1f;5. 類的構造函數6. 類的析構函數7. 數據封裝和訪問修飾符8. 示例&#xff1a;一個簡單的BankAccount類9. 使用g編譯10. 再來一個簡單的C程序11. 定義書籍類…

Linux修煉之路之初識操作系統+基礎指令(1)

目錄 引言 一&#xff1a;對操作系統(OS)的簡單了解 1.操作系統(OS) 是什么 2.操作系統好壞的衡量標準 3.操作系統存在的重要性 4.理解所有在計算機上的操作 二&#xff1a;Linux與windows操作的特點區別 三&#xff1a;基礎指令 1.ls 指令 1.使用 2.常用選項 2.…

AI時代,為什么還要學習編程

在AI時代的浪潮之下&#xff0c;人工智能正逐漸滲透到我們生活的每一個角落&#xff0c;從自動化的客服系統到智能家居控制&#xff0c;再到先進的機器學習和數據分析技術。這一切進步無疑都在提問一個根本性問題&#xff1a;在AI如此先進的今天&#xff0c;為什么我們還需要學…

ICode國際青少年編程競賽- Python-3級訓練場-if else練習

ICode國際青少年編程競賽- Python-3級訓練場-if else練習 1、 for i in range(6):Dev.step(2)Dev.turnLeft()if i ! 1:Dev.step(2)Dev.step(-2)else:Dev.step(-3)Dev.step(3)Dev.turnRight()2、 Dev.step() for i in range(5):Dev.step(2)Dev.turnRight()if i < 1:Dev.s…