Android圖形渲染系統新

語言: CN / TW / HK

Android圖形渲染系統是Android不可或缺的子系統之一,其本身複雜且與其他子系統存在千絲萬縷的聯絡,各種模組眾多,內容繁雜,各個版本都會有一定的更新,很難一篇文章道完天機,後續希望能出個系列文章好好講解內中玄機,本文作為系列的開篇,希望能系統的講解下各模組的機制,雖然之前也寫過相關文章,但是本篇文章帶來了不一樣的內容。

眾所周知手機已是人們生活中不可或缺的一部分,手機也天然的成為了移動端的一個最重要的流量底座,承載著使用者各種精神和物質上的需求,其中互動體驗和感受又是使用者最直接的反應,而渲染系統是保障這一切的根基。

首先我們以官方的一張圖作為切入點

該圖展示了圖形系統的關鍵元件協作流程和圖形資料的流轉:

  • OpenGL ES、MediaPlayer、Camera等生產者生產GraphicBuffer到Surface
  • Surface通過IGraphicBufferProducer把GraphicBuffer跨程序傳輸給消費者SurfaceFlinger
  • SurfaceFlinger根據WMS提供的視窗資訊合成所有的Layer,具體的合成策略由hwcomposerHAL模組決定並實施,
  • 最後也是由該模組送到Display模組,而Gralloc模組則負責分配圖形緩衝區。 

但上圖是16年官方給出的,隨著幾年的更新也引入了一些新的模組,支援了新的圖形庫-Vulkan,Gralloc和BufferQueue也做了相應的支援,我們可以繼續細化下整體流程,全景圖如下:

從上圖可看出整個渲染系統貫穿app和系統層,app在CPU側進行圖形資料的生產,然後交給GPU做渲染處理,最後由SurfaceFlinger和HWC配合進行合成並渲染上屏,其間涉及了多個核心模組的協作,下面我們進行重點的講解: 

Graphic Buffer Producers

產生graphic buffers的生產者. 例如OpenGL ES, Vulkan, Media的影片解碼器,Camera等.

Graphic Buffer Consumers

最核心的消費者便是SurfaceFlinger,它使用OpenGL和Hardware Composer來組合一組surfaces

  • OpenGL ES應用能消費圖形流, 比如camera app消費camera預覽圖形流;
  • 非OpenGL ES應用也能消費, 比如ImageReader類

Canvas

Canvas 是一個2D圖形 API ,是 Android View 樹實際的渲染者。Canvas 又可分為Skia 軟體繪製和 hwui 硬體加速繪製。

Window Manager

用於管理Window.Window是個抽象類,表示一個視窗,其實現是PhoneWIndow。WindowManager 會監督生命週期、輸入和聚焦事件、螢幕方向、轉換、動畫、位置、變形、Z 軸順序以及視窗的許多其他方面。當app通過WindowManager建立一個Window時,WindowManagerService會為每一個Window建立一個Surface,並將各種(包括螢幕資訊,z-order等)資訊傳送給SurfaceFlinger。

Surface

Surface 表示 APP 程序的一個視窗,承載了視窗的圖形資料與SurfaceFlinger側的Layer相對應 。從App側來看不管是 Canvas , OpenGL ES還是Vulkan最終渲染到的目標都是 Surface ,現在比較流行的跨平臺UI框架 Flutter 在 Android 平臺上也是直接渲染到 Surface 。

一個Activity是一個Surface、一個Dialog也是一個Surface。

BufferQueue

安卓圖形渲染設計有一個生成者消費者模式,BufferQueue即是這種模式的寫照。Android 圖形系統包含了兩對生產者和消費者模型,它們都通過 BufferQueue 進行連線:

  • Canvas ,OpenGL ES 和Vulkan生產圖形資料,SurfaceFlinger消費圖形資料。
  • SurfaceFlinger合成所有圖層的圖形資料,Display顯示合成結果。

BufferQueue是連線 Surface 和 Layer 的紐帶,當上層圖形資料渲染到 Surface 時,實際是渲染到了BufferQueue中的一個GraphicBuffer,然後通過IGraphicBufferProducer 把 GraphicBuffer 提交到 BufferQueue ,讓 SurfaceFlinger 進行後續的合成顯示工作。GraphicBuffer代表的圖形緩衝區是由Gralloc模組分配的,並且可以跨程序傳輸(實際傳輸的只是一個指標),為了高效傳輸大塊資料,使用匿名共享記憶體。

BufferQueue的經典工作流程如下:

  • 生產者請求一塊空閒的快取區:dequeueBuffer()
  • 生產者填充快取區並返回給佇列: queueBuffer()
  • 消費者獲取一塊快取區: acquireBuffer()
  • 消費者使用完畢,則返回給佇列: releaseBuffer()

SurfaceFlinger

Android 系統服務,會隨著init程序執行init.rc而建立該服務。負責合成所有 Surface 提供的圖形資料,然後送顯到螢幕。SurfaceFlinger 既是上層應用的消費者,又是 Display 的生產者。功能如下:

  • 分配圖形緩衝區
  • 合成Surface
  • 管理 VSYNC 事件

SurfaceFlinger就是將多個Surface裡的內容進行合成,最後提交到螢幕的後緩衝區,等待螢幕的下一個垂直同步訊號的到來,再顯示到螢幕上。

SurfaceFlinger 負責合成所有的 Layer 並送顯到 Display ,這些Layer主要有三種合成方式:

  • OpenGL ES:把這些圖層合成到 FrameBuffer,然後把FrameBuffer提交給hwcomposer 完成剩餘合成和顯示工作。
  • hwcomposer:通過HWC模組合成部分圖層和FrameBuffer,並顯示到Display。
  • Vulkan:把這些圖層合成到 FrameBuffer,然後把FrameBuffer提交給hwcomposer 完成剩餘合成和顯示工作。

OpenGL

傳統的圖形API,規範了圖形介面,Opengl ES是一個專用於嵌入式裝置的OpenGL,但Opengl本身只提供介面和規範,具體的需要各平臺提供介面層去適配自己的視窗體系,比如Android平臺的EGL。生態好,適用廣泛。

Vulkan

Vulkan是新一代的圖形顯示API。也有業界稱之為“下一代的OpenGL”,是下一代高效能及精細化控制的開放的跨平臺的圖形API。想要更深入瞭解的同學請參考我之前的文章: Vulkan-效能及精細化控制Vulkan-實踐剖析

Vulkan在Android 7.0後也被google支援了,Android上分為三層結構對Vulkan進行了適配支援。

Vulkan 驗證層:在 Vulkan 應用開發期間使用的庫,用於查詢應用在 Vulkan API 的使用方面的錯誤。在找出此類錯誤後,應移除這些庫。

Vulkan 執行時:原生庫 libvulkan.so 提供原生 Vulkan API。Vulkan 執行時的大部分功能由 GPU 供應商提供的驅動程式實現。Vulkan 執行時會封裝驅動程式、提供 API 攔截功能(針對除錯和其他開發者工具)以及管理驅動程式與平臺依賴項之間的互動。

Vulkan 驅動程式:將 Vulkan API 對映到特定於硬體的 GPU 命令以及與核心圖形驅動程式的互動。

Hardware Composer(硬體混合渲染器)

Android中進行視窗(Layer)合成和顯示的HAL層模組,顯示子系統的硬體抽象實現。其內部實現是基於特定裝置的,通常由螢幕硬體裝置製造商 (OEM) 完成。主要用於確定合成緩衝區的最有效方式,SurfaceFlinger 在收集可見層的所有緩衝區後,便會詢問 HWC 應如何進行合成。可分為Client合成和Device合成。SurfaceFlinger 可以將某些合成工作委託給 Hardware Composer,以分擔 GPU 上的工作量。

HAL

硬體抽象層。HAL提供標準介面,給更高級別的介面框架顯示裝置硬體功能。HAL 包含多個庫模組,其中每個模組都為特定型別的硬體元件實現一組介面,例如相機或藍芽等。當框架 API 請求訪問裝置硬體時,Android系統將為該硬體載入相應的庫模組。

Gralloc

含義是 Graphics Alloc 圖形分配, 用於圖形生產時請求分配記憶體.Android 系統在硬體抽象層中提供了一個 Gralloc 模組,封裝了對 Framebuffer 的所有訪問操作。

Gralloc 模組符合 Android 標準的 HAL 架構設計;它分為 fb 和 gralloc 兩個裝置:前者負責開啟核心中的 Framebuffer 、初始化配置,以及提供 post, setSwapInterval 等操作;後者則管理幀緩衝區的分配和釋放。

FrameBuffer

Linux抽象出FrameBuffer這個裝置來供使用者態程序實現直接寫屏。FrameBuffer是顯示卡硬體的抽象,可以通過FrameBuffer的讀寫直接對視訊記憶體進行操作。

FrameBuffer本身不具備任何運算資料的能力,CPU將運算後的結果放到FrameBuffer,就會顯示處理,中間不會對資料做處理。

Linux核心提供了統一的Framebuffer顯示驅動,節點為/dev/graphics/fb 或者 /dev/fb ,以fb0表示第一個 Monitor,這個虛擬裝置將不同硬體廠商實現的真實裝置統一在一個框架下,這樣應用層就可以通過標準的介面進行圖形/影象的輸入和輸出。

微信公眾號首發,歡迎各位code er關注公眾號:江湖修行