定義一臺抽象機器,用于描述 Mali GPU和驅動(dòng)程序軟件對應用程序可見(jiàn)的行為。此機器的用意是為開(kāi)發(fā)人員提供 OpenGL ES API 下有趣行為的一個(gè)心智模型,而這反過(guò)來(lái)也可用于解釋影響其應用程序性能的問(wèn)題。我在本系列后面幾篇博文中繼續使用這一模型,探討開(kāi)發(fā)人員在開(kāi)發(fā)圖形應用程序時(shí)常常遇到的一些性能缺口。 這篇博文將繼續開(kāi)發(fā)這臺抽象機器,探討 Mali GPU系列基于區塊的渲染模型。你應該已經(jīng)閱讀了關(guān)于管線(xiàn)化的第一篇博文;如果還沒(méi)有,建議你先讀一下。 “傳統”方式 在傳統的主線(xiàn)驅動(dòng)型桌面 GPU 架構中 — 通常稱(chēng)為直接模式架構 — 片段著(zhù)色器按照順序在每一繪制調用、每一原語(yǔ)上執行。每一原語(yǔ)渲染結束后再開(kāi)始下一個(gè),其利用類(lèi)似于如下所示的算法: 1. foreach( primitive ) 2. foreach( fragment ) 3. render fragment 由于流中的任何三角形可能會(huì )覆蓋屏幕的任何部分,由這些渲染器維護的數據工作集將會(huì )很大;通常至少包含全屏尺寸顏色緩沖、深度緩沖,還可能包含模板緩沖,F代設備的典型工作集是 32 位/像素 (bpp) 顏色,以及 32 bpp 封裝的深度/模板。因此,1080p 顯示屏擁有一個(gè) 16MB 工作集,而 4k2k 電視機則有一個(gè) 64MB 工作集。由于其大小原因,這些工作緩沖必須存儲在芯片外的 DRAM 中。 每一次混合、深度測試和模板測試運算都需要從這一工作集中獲取當前片段像素坐標的數據值。被著(zhù)色的所有片段通常會(huì )接觸到這一工作集,因此在高清顯示中,置于這一內存上的帶寬負載可能會(huì )特別高,每一片段也都有多個(gè)讀-改-寫(xiě)運算,盡管緩存可能會(huì )稍稍緩減這一問(wèn)題。這一對高帶寬存取的需求反過(guò)來(lái)推動(dòng)了對具備許多針腳的寬內存接口和專(zhuān)用高頻率內存的需求,這兩者都會(huì )造成能耗特別密集的外部?jì)却嬖L(fǎng)問(wèn)。 Mali 方式 Mali GPU 系列采用非常不同的方式,通常稱(chēng)為基于區塊的的渲染,其設計宗旨是竭力減少渲染期間所需的功耗巨大的外部?jì)却嬖L(fǎng)問(wèn)。如本系列第一篇博文中所述,Mali 對每一渲染目標使用獨特的兩步驟渲染算法。它首先執行全部的幾何處理,然后執行所有的片段處理。在幾何處理階段中,Mali GPU 將屏幕分割為微小的16x16 像素區塊,并對每個(gè)區塊中存在的渲染原語(yǔ)構建一份清單。GPU 片段著(zhù)色步驟開(kāi)始時(shí),每一著(zhù)色器核心一次處理一個(gè) 16x16 像素區塊,將它渲染完后再開(kāi)始下一區塊。對于基于區塊的架構,其算法相當于: 1. foreach( tile ) 2. foreach( primitive in tile ) 3. foreach( fragment in primitive in tile ) 4. render fragment 由于 16x16 區塊僅僅是總屏幕面積的一小部分,所以有可能將整個(gè)區塊的完整工作集(顏色、深度和模板)存放在和 GPU 著(zhù)色器核心緊密耦合的快速 RAM 中。 這種基于區塊的方式有諸多優(yōu)勢。它們大體上對開(kāi)發(fā)人員透明,但也值得了解,尤其是在嘗試了解你內容的帶寬成本時(shí): 對工作集的所有訪(fǎng)問(wèn)都屬于本地訪(fǎng)問(wèn),速度快、功耗低。讀取或寫(xiě)入外部 DRAM 的功耗因系統設計而異,但對于提供的每 1GB/s 帶寬,它很容易達到大約 120mW。與這相比,內部?jì)却嬖L(fǎng)問(wèn)的功耗要大約少一個(gè)數量級,所以你會(huì )發(fā)現這真的大有關(guān)系。 混合不僅速度快,而且功耗低,因為許多混合方式需要的目標顏色數據都隨時(shí)可用。 區塊足夠小,我們實(shí)際上可以在區塊內存中本地存儲足夠數量的樣本,實(shí)現 4 倍、8 倍和 16 倍多采樣抗鋸齒1。這可提供質(zhì)量高、開(kāi)銷(xiāo)很低的抗鋸齒。由于涉及的工作集大小(一般單一采樣渲染目標的 4、8 或 16 倍;4k2k 顯示面板的 16x MSAA需要巨大的 1GB 工作集數據),少數直接模式渲染器甚至將 MSAA 作為一項功能提供給開(kāi)發(fā)人員,因為外部?jì)却娲笮『蛶捦ǔе缕涑杀具^(guò)于高昂。 Mali 僅僅需要將單一區塊的顏色數據寫(xiě)回到區塊末尾的內存,此時(shí)我們便能知道其最終狀態(tài)。我們可以通過(guò) CRC 檢查將塊的顏色與主內存中的當前數據進(jìn)行比較 — 這一過(guò)程叫做“事務(wù)消除”— 如果區塊內容相同,則可完全跳過(guò)寫(xiě)出,從而節省了 SoC 功耗。我的同事 Tom Olson 針對這一技術(shù)寫(xiě)了一篇 優(yōu)秀的博文,文中還提供了“事務(wù)消除”的一個(gè)現實(shí)世界示例(某個(gè)名叫“憤怒的小鳥(niǎo)”的游戲;你或許聽(tīng)說(shuō)過(guò))。有關(guān)這一技術(shù)的詳細信息還是由 Tom 的博文來(lái)介紹;不過(guò),這兒也稍稍了解一下該技術(shù)的運用(僅“多出的粉色”區塊由 GPU 寫(xiě)入 - 其他全被成功丟棄)。 我們可以采用快速的無(wú)損壓縮方案 — ARM 幀緩沖壓縮 (AFBC) — ,對逃過(guò)事務(wù)消除的區塊的顏色數據進(jìn)行壓縮,從而進(jìn)一步降低帶寬和功耗。這一壓縮可以應用到離屏 FBO 渲染目標,后者可在隨后的渲染步驟中由 GPU 作為紋理讀回;也可以應用到主窗口表面,只要系統中存在兼容 AFBC 的顯示控制器,如 Mali-DP500。 大多數內容擁有深度緩沖和模板緩沖,但幀渲染結束后就不必再保留其內容。如果開(kāi)發(fā)人員告訴 Mali 驅動(dòng)程序不需要保留深度緩沖和模板緩沖2— 理想方式是通過(guò)調用 glDiscardFramebufferEXT (OpenGL ES 2.0) 或 glInvalidateFramebuffer (OpenGLES 3.0),雖然在某些情形中可由驅動(dòng)程序推斷 — 那么區塊的深度內容和模板內容也就徹底不用寫(xiě)回到主內存中。我們又大幅節省了帶寬和功耗! 上表中可以清晰地看出,基于區塊的渲染具有諸多優(yōu)勢,尤其是可以大幅降低與幀緩沖數據相關(guān)的帶寬和功耗,而且還能夠提供低成本的抗鋸齒功能。那么,有些什么劣勢呢? 任何基于區塊的渲染方案的主要額外開(kāi)銷(xiāo)是從頂點(diǎn)著(zhù)色器到片段著(zhù)色器的交接點(diǎn)。幾何處理階段的輸出、各頂點(diǎn)可變數和區塊中間狀態(tài)必須寫(xiě)出到主內存,再由片段處理階段重新讀取。因此,必須要在可變數據和區塊狀態(tài)消耗的額外帶寬與幀緩沖數據節省的帶寬之間取得平衡。 當今的現代消費類(lèi)電子設備正大步向更高分辨率顯示屏邁進(jìn);1080p 現在已是智能手機的常態(tài),配備Mali-T604 的 Google Nexus 10 等平板電腦以 WQXGA (2560x1600) 分辨率運行,而 4k2k 正逐漸成為電視機市場(chǎng)上新的“不二之選”。屏幕分辨率以及幀緩沖帶寬正快速發(fā)展。在這一方面,Mali 確實(shí)表現出眾,而且以對應用程序開(kāi)發(fā)人員基本透明的方式實(shí)現 - 無(wú)需任何代價(jià),就能獲得所有這些好處,而且還不用更改應用程序! 在幾何處理方面,Mali 也能處理好復雜度。許多高端基準測試正在接近每幀百萬(wàn)個(gè)三角形,其復雜度比 Android 應用商店中的熱門(mén)游戲應用程序高出一個(gè)(或兩個(gè))數量級。然而,由于中間幾何數據的確到達主內存,所以可以應用一些有用的技巧和訣竅,來(lái)優(yōu)化 GPU 性能并充分發(fā)揮系統能力。這些技巧值得通過(guò)一篇博文來(lái)細談,所以我們會(huì )在這一系列的后續博文中再予以介紹。 小結 在這篇博文中,我比較了桌面型直接模式渲染器與 Mali 所用的基于區塊方式的異同,尤其探討了兩種方式對內存帶寬的影響。 |