Android14 - 繪制系統 - 概覽

從Android?12開始,Android繪制系統有結構性變化,?在繪制的生產消費者模式中,新增BLASTBufferQueue,客戶端進程自行進行queue的生產和消費,隨后通過Transation提交到SurfaceFlinger,如此可以使得各進程將緩存提交到SufrfaceFlinger后合并到同一事務后同步提交,在同一幀生效。實際上,從Android12到Android14整個繪制系統各個環節也都或大或小調整,比如Android13發布了1.3版本的Vulkan,?Android14新增了TextureView,等等。本文基于Android14

Android?繪制系統整體架構:

從上到下可以理解為“生產者(Producer)”到“消費者(Consumer)”處理過程

首先WindowManagerService角度每個窗口稱為Window一個Window一般一個APP頁面或者Status Bar或者Navigation Bar或者WallPaper這些一個個Window。WindowManagerService(WMS)作為服務端對所有客戶端窗口添加、層級、布局等進行統一管理WMS每個Window對應一個SurfaceSurface可以理解圖像數據緩存持有者以及Canvas持有者Canvas畫布提供繪制各種圖形能力供開發使用。一個客戶端窗口在建立之初,會先向WMS去申請一個SurfaceWMS創建Surface之后,通過binder返回客戶端客戶端Surface后,會去創建一個BLASTBufferQueue管理圖像內存申請每次要使用Surface的Canvas進行繪制前,需要BLASTBufferQueue申請一塊內存(dequeue),我們這里稱為Buffer,然后生成圖像數據寫入Buffer。這個向BLASTBufferQueue申請Buffer并寫入圖像數據的過程,可以認為是“生產”階段。隨后,enqueue這個buffer,將其提交SurfaceFlinger去合成。這個階段可以理解圖像Buffer的“消費”階段

SurfaceFlinger(SF負責Hardware溝通維護著設備掛載、VSync信號收發、Layer合成工作。WMS每個SurfaceSurfaceFlinger對應生成一個Layer對象客戶端將某個Surface上的Buffer提交SurfaceFlinger,實際上就是更新對應LayerBuffer數據SurfaceFlinger調用HWComposer將這些Layer進行合成顯示屏幕

AndroidHAL提供稱為一個Hardware Composer組件用于隔離具體硬件的交互。Hardware Composer簡稱HWComposerHWC2(之所以2早期已有一個HWC版本支持軟件合成)。SurfaceFlingerLayer數據交給HWComposer,各廠商來負責HWComposer合成接口具體實現合成完畢數據提交屏幕設備緩存(一般稱為Frame?Buffer)屏幕顯示畫面

上面過程可以拆解為幾部分

  1. Surface創建與管理
  2. 客戶端(EndPoint)繪制(Draw)渲染(Render)圖像
  3. 第三部分是硬件Composition(合成)工作
  4. Vsync:由硬件產生信號用于同步framebuffer生產消費SurfaceFlingerVsync進行使用管理向上分發APPVsync是不斷繪制驅動力,也是圖像緩存有序投送到屏幕的重要機制。

現在分別討論下四部分

  1. Surface的創建與管理

Surface創建過程中有幾個角色貫穿其中

PhoneWindow一個Activity對應一個PhoneWindow代表一個應用窗口AMS創建Activity之初PhoneWindow服務端對應window對象(ActivityRecord)已經添加WMS

ViewRootImpl:其主要作用服務端通信承接外部觸發繪制調用從而從上往下整個View樹進行繪制可以把ViewRootImp理解為View的調度者ViewRootImp邏輯上View Hierarchy最頂層并不是一個真正View持有一個View--DecorViewDecorView才是真正ViewView最上層,包含著Activity的畫面內容。在Activity的resume階段,ViewRootImplrelayout方法會將DecorView添加到WMS中,這樣Activity的內容就顯示了出來。邏輯上,我們可以把DecorView也理解為一個Window。Activity對應一個PhoneWindow,通過ViewRootImplDecorView在WMS端添加PhoneWindowWindow。

WMS的Session客戶端一個進程對應WMS一個Session客戶端持有Sessionbinder客戶端窗口添加事務客戶端都是通過這個SessionWMS通信

WindowContainerWMS管理系統整體Window體系包括位置層級關系通過WindowContainer這個表達一個WindowDisplayContent代表一個屏幕級別WindowDisplayArea代表一塊屏幕一塊區域比如平板等大屏幕設備可能一塊屏幕上同時顯示多個應用區域此時就用DisplayArea表達WindowToken簡單理解為對應一個客戶端Window比如一個應用Activity,這里需要注意的是,Activity的WindowToken是作為ActivityRecord存在的,也就是說ActivityRecord是WindowToken的子類。而Activity具體內容承載者,DecorView對應WindowState上面所有DisplayContentDisplayAreaWindowTokenWindowState都是WindowContainer子類,這些Window在WMS內是以window樹的形式組織起來的。事實上DisplayContent下面還有一個層級稱為Feature具體層級結構Android12 - WMS之WindowContainer樹(DisplayArea)_android windowcontainer-CSDN博客客戶端通過Session接口調用添加DecorViewWMS生成一個對應WindowState對象將其作為Activity對應ActivityRecord(也就是WindowToken)window

SurfaceControl:在WMS端,每個WindowContainer對應一個SurfaceControlSurfaceControlWMS端管理Surface具體對象,在WMS端,可以理解一個SurfaceControl就代表一個Surface。SurfaceControl在SurfaceFlinge端對應一個Layer,持有一個layer的句柄handle。所有繪制動作最后提交SurfaceFinger作為Layer去合成。SurfaceControl作用或者Surface作用主要客戶端窗口SurfaceFlingerLayer關聯起來客戶端Add一個DecorView WMS對應創建WindowState同時創建一個SurfaceControl、Layer隨后SurfaceControl返回客戶端客戶端拿到SurfaceControl之后轉換成Surface后續繪制就在這個Surface進行

SurfaceComposerClient是一個Binder主要作用是SurfaceControl調用SurfaceFlinger過程中,作為一個通道角色由于SurfaceControlWMS客戶端持有所以客戶端WMS都可以通過這個通道調用SF比如Layer創建、Graphihc?Buffer提交

1. 客戶端繪制和渲染

客戶端通過Surface中提供的Canvas進行繪制Canvas基于Skia的SKCanvas。Skia(https://skia.org/)是Google管理的開源2D(也可以支持3D)圖像庫,目前AndroidGoogle ChromeChromeOS、Mozilla?FireFoxFireFoxOS使用Skia作為繪制引擎。Skia可以集成OPEN?GL和Vulkan進行3D繪制Android Q以后Skia作用加強即使硬件加速場景中繪制也會封裝成Skia的GrOpList再提交給GPU。Android 14 Skia目錄external/skia

渲染的過程是將畫好的圖像,進行柵格化(Rasterizer),變成一個個像素,這是一個非常耗時的過程。Android 3以前支持軟件渲染Software Render過程如下:

APPViewonDraw階段使用Canvas繪制通過Skia進行軟件柵格化,通過CPU計算,將繪制內容轉化成一個個像素信息,隨后投送給屏幕進行顯示。由于軟件渲染效率低,當下軟件渲染只是作為兼容方案得以保留,默認使用硬件加速。

硬件加速的流程簡單表述如下:

Android硬件加速相關能力封裝hwui組件hwui地址platform/frameworks/base/libs/hwui

硬件加速模式下APPonDraw通過Canvas繪制內容最終封裝DisplayList一個個GrOp繪制命令然后通過OpenGL或者Vulkan交由GPU進行渲染隨后結果投送屏幕顯示具體使用OpenGL還是Vulkan可選擇早期Android使用OpenGL由于Vulkan支持多線程渲染性能方面優勢Android逐漸傾向使用Vulkan進行渲染另外,在哪些維度上進行硬件加速也是可選

整體使用硬件加速情況如果某個View繪制暫時不支持硬件加速,或者在某些位移動畫上為了減少渲染成本,可以動過設置ViewlayerType?=?LAYER_TYPE_SOFTWARE單純某個特定View使用Software?Render。

硬件加速除了利用GPU加速渲染效率 本身計算渲染范圍相較軟件渲染更加高效軟件渲染每次更新一個View局部將使得整個View hierarchy重新渲染硬件加速標注變化部分,所謂damage?area,將繪制指令保存DisplayList中,如此大大提高渲染速度

OpenGL?ES VS?Vulkan

以下OpenGL ESVulkanAndroid發布版本歷史

Vulkan作為一個面向更低級別規范、跨平臺的API,可以提供更細粒度的內存管理和資源管理

以下VulkanOpenGL ES使用率(from?GDC?2023?https://www.youtube.com/watch?v=C7OjI7CpjLw&t=1188s):

對于未來計劃OpenGL ES將不會再有功能更新功能只會Vulkan支持因此Vulkan未來Android主推渲染引擎

無論OpenGL還是Vulkan都需要GPU的支持例如常見的車載高端芯片高通8155明確標明支持:?OpenGL?ES?3.xVulkanhttps://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/qul7413_sa8155_productbrief_r4.pdf

2. HW Composer(HWC2)圖像合成

前面提到過,每個window對應一個SF中的Layer合成(Composition)工作就是這些Layer進程合并一個完整屏幕內容提交給硬件屏幕顯示出來大概過程如下

頁面LayerStatusBarNavigationBar中間APP內容頁面,其中可能會有重疊的部分,稱為Overlay。Composition工作就是將這三個Layer合并一個畫面,計算重疊部分的顏色,提交屏幕顯示出來

合成工作發生在渲染后的內容提交給SurfaceFlinger之后。大致流程如下

合成硬件合成的部分軟件合成部分。硬件合成除了更高效的同時,可以合成工作GPU解放出來,提高GPU效率,節省能耗。嵌入式設備的SOC中,硬件合成一般獨立DPU(Display?Processing)完成

比如高通SA8155這款SOC布局如下

其中GPU部分負責渲染,“Dispay?Processing”的部分用來處理合成工作

由于硬件合成Layer數量是限制例如高通QCS2290支持4個Layer、AMD有的芯片支持7)以及Layer的PixelFormat(比如支持PIXEL_FORMAT_RGBA_8888不支持YUV)是限制的,因此硬件合成之前如果合成Layer過多或者Format不滿足需要使用GPU先進行一輪軟件合成合并或轉換一些Layer格式

軟件合成過程。(Google?I/O?'18)

4. VSYNC

VSync簡介:

首先關注兩個重要概念

refresh?rate - 60Hz 代表每秒鐘屏幕可以更新多少次這一值早期是固定依賴于硬件現代旗艦設備屏幕支持多個刷新率60Hz~165Hz不等而且是可以App定制刷新率

frame?rate秒鐘GPU可以繪制多少越大越好

VSync一個通用概念LinuxPC移動設備實現

想象一下繪制過程是這樣的:GPU繪制數據,將繪制結果投擲給屏幕顯示出來

問題是refresh rateFrame Rate并不保證一致頻率,也就是是說GPU渲染的時間并不能保證就正好是16ms(60Hz)內完成的。如果只有一塊內存(Frame?Buffer)用來交換數據,假如Refresh?Rate大于Frame Rate由于GPU從上到下寫這塊內存的在當屏幕來取數據的時候,GPU剛剛在舊基礎上一半此時就會出現圖片撕裂問題

解決方法是雙緩存方案

提供Back?Buffer和Frame?Buffer兩個緩存,屏幕始終Frame?Buffer數據顯示GPU往Back BufferGPU完全數據寫好Back Buffer整個拷貝Frame Buffer這樣就能保證屏幕每次完整

此時仍有一個問題如果GPU的Frame?Rate大于屏幕Refresh Rate那么屏幕下一可能GPU寫完好幾就會出現丟幀現象此時就需要VSync

屏幕根據自己的刷新頻率,去給上層發送一個VSync信號GPU拿到這個VSync信號繪制這樣就能同步屏幕上層繪制節奏

如果屏幕Refresh Rate大于GPUFrame Rate怎么

屏幕將會仍然顯示舊幀。比如中間方框兩次刷新屏幕仍然顯示前一次內容

Android的VSYNC

實際上Android的VSync要復雜得多,主要由SurfaceFlinger負責實現。通過之前的介紹我們知道一幀的繪制過程有APP繪制渲染SurfaceFlinger合成Display硬件讀取幀緩存顯示圖片三個階段,如果每一個階段都依賴VSync信號來執行,那可能會出現這種情況:

也就是VSync1時候APP正在繪制渲染SF還沒有可以合成東西所以什么不做等到VSync2時候Render1工作已經完成可以合成VSync3時候合成做完了才可以顯示屏幕上繪制渲染顯示經歷3VSync面對這種情況AndroidVSync設計如下

有三種信號

HW_VSYNC_[ID]底層硬件按Refresh?Rate的頻率發出,一般為60Hz、90Hz、120H等等,隨后會通過HWC通知SurfaceFlinger

VSYNC-app:SurfaceFlinger通知給上層應用VSYNC用于控制和驅動應用繪制渲染

VSYNC-sf:通知給SurfaceFlinger自身的,用于合成Layer信號

VSYNC-appVSYNC-sfHW_VSYNC_[ID]并不是同步發送而是有一定延遲,稱為相位差HW_VSYNC_[ID]VSYNC-app發出時間差稱為app phaseHW_VSYNC_[ID]VSYNC-sf發出時間差稱為sf phase這種設計好處是如果同一個VSync周期內,經sf?phase后在執行合成時恰好前一步Render完成就可一個周期完成不用非得下一個VSync

另外Android并非直接硬件HW_VSYNC_[ID]信號直接分發應用SurfaceFlinger而是通過先收集HW_VSYNC_[ID]樣本,再根據屏幕Refresh Rate、預先配置的相位差等信息,經過計算模擬出來VSYNC-appVSYNC-sf

由于只需要一定的硬件VSync樣本便可以模擬出預期VSYNC-appVSYNC-sf因此并不需要一直HW_VSYNC_[ID]信號收到足夠樣本(在Android?14中為6個)就可以關閉硬件VSync每次合成數據提交屏幕返回一個硬件VSync時間戳(PresentFence),此時SF對比當前模擬VSync硬件VSync是否誤差過大如果過大重新打開硬件VSync收集樣本重新計算另外每次終端應用主動請求VSync判斷前后兩次模擬VSync時間差是否超過750ms如果重新請求打開硬件VSyncsystrace硬件VSyncTAGHW_VSYNC_ON_[ID]

參考資料https://source.android.com/docs/core/graphics/implement-vsync

可變刷新率

現代旗艦機屏幕刷新率可變,比如Pixel?5:

可以看到屏幕是支持60Hz90Hz兩種刷新率

而且應用層可以在應用級別、窗口級別指定具體刷新率經過應用指定最終刷新率并不一定指定而是經過SurfaceFlinger綜合計算得出具體見https://developer.android.com/media/optimize/performance/frame-rate

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

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

相關文章

【vue3+elementuiplus】el-select下拉框會自動觸發校驗規則

場景:編輯彈框省份字段下拉框必填,觸發方式change,有值第一次打開不會觸發校驗提示,關閉彈框再次打開觸發必填校驗提示,但是該字段有值 問題的原因是:在關閉彈層事件中,我做了resetfileds&…

SpringBoot + MybatisPlus

SpringBoot MybatisPlus 整合記錄 1. 硬件軟件基本信息2. 相關鏈接3. 通過idea快速生成一個Springboot項目4. 啟動報錯問題解決問題一:Springboot啟動的時候報錯提示 “沒有符合條件的Bean關于Mapper類型”問題二:啟動的時候提示需要一個Bean&#xff0…

電磁仿真--CST網格介紹

1. 簡介 網格會影響仿真的準確性和速度,花時間理解網格化過程是很重要的。 CST 中可用的數值方法包括FIT、TLM、FEM、MoM,使用不同類型的網格: FIT和TLM:六面體 FEM:四面體、平面 MoM:表面 CFD&#…

深入理解與防御跨站腳本攻擊(XSS):從搭建實驗環境到實戰演練的全面教程

跨站腳本攻擊(XSS)是一種常見的網絡攻擊手段,它允許攻擊者在受害者的瀏覽器中執行惡意腳本。以下是一個XSS攻擊的實操教程,包括搭建實驗環境、編寫測試程序代碼、挖掘和攻擊XSS漏洞的步驟。 搭建實驗環境 1. 安裝DVWA&#xff…

【408真題】2009-16

“接”是針對題目進行必要的分析,比較簡略; “化”是對題目中所涉及到的知識點進行詳細解釋; “發”是對此題型的解題套路總結,并結合歷年真題或者典型例題進行運用。 涉及到的知識全部來源于王道各科教材(2025版&…

推薦一個快速開發接私活神器

文章目錄 前言一、項目介紹二、項目地址三、功能介紹四、頁面顯示登錄頁面菜單管理圖表展示定時任務管理用戶管理代碼生成 五、視頻講解總結 前言 大家好!我是智航云科技,今天為大家分享一個快速開發接私活神器。 一、項目介紹 人人開源是一個提供多種…

SCSS配置教程

SCSS(Sassy CSS)是 Sass(Syntactically Awesome Stylesheets)的一種語法,它是一種 CSS 預處理器,允許你使用變量、嵌套規則、混合(mixin)、函數等高級功能來編寫 CSS,從而…

Golang | Leetcode Golang題解之第112題路徑總和

題目: 題解: func hasPathSum(root *TreeNode, sum int) bool {if root nil {return false}if root.Left nil && root.Right nil {return sum root.Val}return hasPathSum(root.Left, sum - root.Val) || hasPathSum(root.Right, sum - roo…

C++常見知識點總結

常見字符 * 注釋:/* 這是一個注釋*/乘法:a * b取值運算符:*指針變量,int a 4,*a ????指針變量:數據類型 *變量名, int *no &bh&#xff0…

SAP揭秘者-怎么執行生產訂單ATP檢查及其注意點

文章摘要: 上篇文章給大家介紹生產訂單ATP檢查的相關后臺配置,大家可以按照配置步驟去進行配置,配置完之后,我們接下來就是要執行ATP檢查。本篇文章具體給大家介紹怎么來執行生產 訂單ATP檢查及其注意點。 執行生產訂單ATP檢查的…

Qt for android 獲取USB設備列表(二)JNI方式 獲取

簡介 基于上篇 [Qt for android 獲取USB設備列表(一)Java方式 獲取], 這篇就純粹多了, 直接將上篇代碼轉換成JNI方式即可。即所有的設備連接與上篇一致。 (https://listentome.blog.csdn.net/article/details/139205850) 關鍵代碼…

Android卡頓丟幀低內存與adb shell內存狀態

Android卡頓丟幀低內存與adb shell內存狀態 卡頓丟幀除了CPU/GPU層面,另外,也需要特別注意整機低內存情況。kswapd0 是一個內核工作線程,內存不足時會被喚醒,做內存回收工作。 當內存頻繁在低水位的時候,kswapd0 會被頻…

webgl three 項目常用操作

分組 const group1 new THREE.Group(); //所有高層樓的父對象group1.name "高層";for (let i 0; i < 5; i) {const geometry new THREE.BoxGeometry(20, 60, 10);const material new THREE.MeshLambertMaterial({color: 0x00ffff});const mesh new THREE.Me…

Linux基礎(六):Linux 系統上 C 程序的編譯與調試

本篇博客詳細分析&#xff0c;Linux平臺上C程序的編譯過程與調試方法&#xff0c;這也是我們后續程序開發的基礎。 目錄 一、第一個hello world程序 1.1 創建.c文件 1.2 編譯鏈接 運行可執行程序 二、編譯鏈接過程 2.1 預編譯階段 2.2 編譯階段 2.3 匯編階段 2.4 鏈…

一千題,No.0025(Chess For Three)

描述 Three friends gathered to play a few games of chess together. In every game, two of them play against each other. The winner gets 2 points while the loser gets 0, and in case of a draw, both players get 1 point each. Note that the same pair of playe…

【MySQL精通之路】SQL語句(3)-鎖和事務語句

目錄 1.START TRANSACTION、COMMIT和ROLLBACK語句 2.無法回滾的語句 3.導致隱含COMMIT的語句 4.SAVEPOINT、ROLLBACK TO SAVEPOINT和RELEASE SAVEPOINT語句 5.LOCK INSTANCE FOR BACKUP和UNLOCK INSTANCE語句 6.LOCK TABLE和UNLOCK TABLES語句 6.1 表鎖獲取 6.2 表鎖釋放…

qemu+gdb調試linux內核

打開CONFIG_DEBUG_INFO,編譯內核 通過圖形菜單配置該宏,執行make menuconfig。 kernel hacking —> compile-time checks and compiler options —> compile the kernel with debug info 驗證是否打開成功,grep -nr “CONFIG_DEBUG_INFO” .config。 打開成功,然后…

plsql 學習

過程化編程語言 賦值&#xff1a;&#xff1a; ||&#xff1a;連接符號 dbms_output.put_line() :輸出的語句 var_name ACCOUNTLIBRARY.USERNAME%type; 變量名&#xff1b;某個表的數據類型&#xff1b;賦值給變量名 用下面的方法更好用 異常exception 循…

力扣HOT100 - 75. 顏色分類

解題思路&#xff1a; 單指針&#xff0c;對數組進行兩次遍歷。 class Solution {public void sortColors(int[] nums) {int p 0;int n nums.length;for (int i 0; i < n; i) {if (nums[i] 0) {int tmp nums[i];nums[i] nums[p];nums[p] tmp;p;}}for (int i p; i …

java庫和包的概念

在Java中&#xff0c;"庫"和"包"是兩個不同的概念&#xff0c;但它們之間存在著密切的關聯。 庫&#xff08;Library&#xff09; 定義&#xff1a;庫是一組已經編寫好的代碼和資源&#xff0c;用于解決特定的問題或提供特定的功能。它可以包含一個或多個…