Chromium GPU資源共用

2023-10-25 12:00:54

資源共用指的是在一個 Context 中的建立的 Texture 資源可以被其他 Context 所使用。一般來講只有相同 share group Context 建立的 Texture 才可以被共用,而 Chromium 設計了一套允許不同 share group 並且跨程序的 Texture 共用機制。

Chromium 中有新舊兩套共用 Texture 的機制,一套是 Mailbox 機制,一套是 SharedImage 機制。

1. Mailbox 機制

Mailbox 機制由 CHROMIUM_texture_mailbox 擴充套件提供,它定義了一種在不同Context之間共用 Texture 物件中的圖片資料的方式,不管這些Context是否處於相同的share group

它定義了2個方法:

 

glProduceTextureDirectCHROMIUM 方法傳入一個當前Context中已經存在的 texture 物件,然後返回一個指向該texture的 mailbox。後續可以在其他的Context中使用 glCreateAndConsumeTextureCHROMIUM 方法通過這個 mailbox 建立一個新的 texture 物件,新物件存在於新的 Context 中。結合 Command Buffer,可以實現跨程序共用Texture的效果。

Mailbox 類本身是一個定長的位元組陣列,作為資源的唯一識別符號,預設是16位元組,系統全域性唯一,可以跨程序。

Mailbox 機制使用起來非常方便,但是它對 service 端的執行環境依賴非常嚴重,比如要求 service 端的所有 Context 都必須屬於相同 share group,這導致service端在某些平臺上需要使用Virtual Context或者很多的同步機制才能實現,而這些會導致效能損失。再加上這種機制基於GL,無法很好的支援Vulkan,因此 Mailbox 機制已經被標記為 deprecated,在當前的 Chromium 中只有 media 模組還在使用。新程式碼應該使用 SharedImage 機制。

2. SharedImage 機制

ShareImage 機制從2018年開始引入,設計用來取代 Mailbox 機制並且支援 Vulkan。它引入了一套 client 端的 SharedImage 介面以及一個新的GL擴充套件 CHROMIUM_shared_image

主要介面為 SharedImageInterface,用來建立 shared images,定義如下:

 

這是一個 client 端的介面,可以通過 gpu::GpuChannelHost 來獲取到。對它的呼叫會通過 IPC 介面傳送到 service 端,service 端會使用合適的機制來儲存 SharedImage 的資料,比如GL Texture,GMB(GpuMemoryBuffer)等。

CreateSharedImage 方法建立一個新的 SharedImage 並返回一個 mailbox 指向它。UpdateSharedImage 方法更新指定的 SharedImage 的屬性。DestroySharedImage 銷燬指定的 SharedImage,釋放相關記憶體。

在client端,通過 CHROMIUM_shared_image 擴充套件提供的方法來讀寫 SharedImage 資料。Mailbox 機制中 CHROMIUM_texture_mailbox 擴充套件提供的方法也可以用來存取 SharedImage,因為 SharedImage 機制相容了 Mailbox 機制。但應該儘量比避免這樣使用,因為 Mailbox 機制已經過時了。在 service 端也可以用這種方法來存取 ShareImage。

在servcie端,SharedImage 實現了大概3類儲存機制,分別為 GLTexture/EGLImage,GMB 和 VulkanImage,這三大類又被抽象為了很多種小類。下面這些都是 SharedImage 可能的儲存後端:

其中 gpu::SharedImageBackingGLTexture 使用 GL Texture 來儲存 SharedImage 資料。gpu::SharedImageBackingEglImage 使用 EGLImage 來儲存資料。gpu::SharedImageBackingAHB 僅用於 Android 平臺,使用 Android 提供的 AHardwareBuffer 來儲存資料。gpu::ExternalVkImageBacking 對接 Vulkan。gpu::SharedImageBackingGLImage 比較特殊,它表示使用 gpu::GLImage 類來進行儲存,gpu::GLImage 又抽象了不同的儲存後端,最終也可能使用 GL Texture。

SharedImage 機制本質上抽象了 GPU 的資料儲存能力。即允許應用直接把資料儲存到 GPU (GPU 能存取到的記憶體)中,以及直接從 GPU 中讀取資料,並且允許跨過shared group邊界。理解了這一點,應該比較容易想到哪些場景可以使用 SharedImage 機制,下面這些是 Chromium 中使用 SharedImage 機制的一些場景:

  1. CC模組: 先將畫面 Raster 到 SharedImage,然後再傳送給 Viz 進行合成。
  2. OffscreenCanvas: 先將 Canvas 的內容 Raster 到 SharedImage,然後再傳送給 Viz 進行合成。
  3. 圖片處理/渲染: 一個執行緒將圖片解碼到 GPU 中,另一個執行緒使用 GPU 來修改或者渲染圖片。
  4. 視訊播放: 一個執行緒將視訊解碼到 GPU 中,另一個執行緒來渲染。

下面介紹2個操作 ShareImage 的擴充套件。需要注意的是在使用這些擴充套件方法之前都先要有一個指向 SharedImage 的 mailbox,可以使用 SharedImageInterface 介面建立,也可以是從其他地方傳過來。

4. CHROMIUM_shared_image 擴充套件

CHROMIUM_SHARED_IMAGE 擴充套件定義了以下4個方法:

 

glCreateAndTexStorage2DSharedImageCHROMIUM* 方法根據傳入的 mailbox 建立一個新的 Texture 物件。然後應用可以使用 glBeginSharedImageAccessDirectCHROMIUM 方法獲取讀/寫 texture 物件的許可權,然後使用常規的讀寫texture的GL命令存取texture的內容,比如glGetTexImageglReadPixelsglTexImage2D等或者使用skia來間接存取texture的內容。操作結束之後,呼叫 glEndSharedImageAccessDirectCHROMIUM 方法釋放許可權。

這些介面用於 GPU-R 機制下的 Raster,這種 Raster 機制已經被 OOP-R Raster 機制替代,並且在2022年2月份被移除,這裡只用於演示舊版本 GPU-R 方式的 Raster:

 5. CHROMIUM_raster_transport

glBeginRasterCHROMIUM 方法表示要開始執行 Raster 操作了,Raster的結果存放到傳入的 mailbox 對應的 SharedImage 中。glRasterCHROMIUM 將 cc::DisplayItemList 序列化後傳送到service端。引數raster_shm_id指向儲存 cc::DisplayItemList 序列化資料的共用記憶體。glEndRasterCHROMIUM 結束 Raster 操作。

這些介面用於 OOP-R(Out-Of-Process Raster) 機制下的 Raster。關於 OOP-R 見後續檔案, 下面的程式碼演示使用 OOP-R 介面建立 SharedImage:

6. SharedImage 架構設計

 

 SharedImage 被設計用於多程序架構,Client 端可以有多個,比如 Browser/Render/Gpu 程序都可以作為 Client 端,Service 端只能有一個,它執行在 Gpu 程序中。Client 和 Servcie 通過 IPC 進行通訊。Client 端的介面主要包括 SharedImageInterface 和 2 個擴充套件。Service 端將資料儲存在基於不同技術實現的 SharedImageBacking 中。

7. SharedImage 實現原理

 8. 總結

在當前的 Chromium 中,Mailbox 機制是建立在 SharedImage 機制之上的。舊的 Mailbox 機制的介面正在被廢棄(Mailbox 類本身並不會被廢棄),在新的程式碼中應該使用新的 SharedImage 介面。

在所有需要「分階段」渲染的場合都可以使用 SharedImage 機制,在需要從 GPU 讀取資料的場合也可以使用 SharedImage 機制。SharedImage 機制只提供記憶體的管理,應用可以使用常規的讀寫GPU資料的方式來讀寫SharedImage中的資料。

9. 參考文獻