為什么每一幀都清除畫布會提高性能?
是否需要glClear
在絕大多數的渲染代碼中,都會在每一幀繪制前去清空畫布(OpenGL的glClear,或Metal的MTLLoadActionClear)。今天和一個朋友聊到這里,他就懷疑這是一個冗余操作,實際上他做渲染相關很久了,我沒想到他竟然會覺得這是錯的。我和他爭論的焦點是每一幀都清空畫布是否適合所有平臺(我是做iOS,他做PC),他的核心論據是他聲稱以前看過一個論壇的文章,在GPU操作時盡量減少glClear是有益的。說實話他這么一說我就虛了,畢竟PC上的驅動版本繁雜,反而我有主觀臆斷的嫌疑,我幾乎要被他說服。
轉念一想,我記得WebKit就會在繪制前清空畫布,這種級別的庫應該不會犯錯吧。休戰一天后,我查了大量資料,確認每一幀繪制前清空畫布是必要的。
glClear的實現
其實他說的論點也對,只是針對比較老板本的驅動才有效。
早期的實現,名副其實:它會寫FBO對應的顯存,改成你設定的值,在混合時一來一回顯然這是一個比較重的操作。
目前的實現,名不副實:它只是標記對應的顯存時clear狀態,當后續的操作去讀取時,會返回一個on-fly的值,這個值就是你的設定值。這個過程實際上并沒有真的占用總線,因為沒有什么實質的操作,在GPU上就完成了。
也就是說就算在IMR下,調不調glClear的差別不大,你就算調了,也只是多了一個標記內存的操作,這在硬件層面不算個事。但是在TBR/TBDR上,情況有所不同。
TBR/TBDR
在TBR/TBDR的GPU架構下,tile在每次渲染前會讀取FBO的值,再這個基礎上做繪制,最后把結果寫到屏幕數據(或者是寫到新的FBO)上。
這么做的原因是GPU默認你需要上一幀的畫面,來完成混合等操作,這部分工作是在tile中完成的。
而glClear會省去tile讀取上一幀數據的操作,也就是圖中的第2個步驟。這樣就少了一次GPU通過總線讀顯存的操作,這樣會提升GPU幀率和減少GPU發熱,畢竟移動端的顯存帶寬小是GPU操作的一大掣肘。
glClear很有必要
由上,在一個渲染模塊中,每一幀渲染前都clear都是合理的,因為它在最差的情況下,也只是和不clear性能相當。