紋理內(nèi)存優(yōu)化

2020-02-13 17:51 更新

內(nèi)存過大導(dǎo)致的問題

游戲運行時占用的內(nèi)存大小,是衡量游戲性能的一個非常重要的指標。游戲如果占用的內(nèi)存過大,會導(dǎo)致以下的問題:

  1. 發(fā)熱,發(fā)燙。過多的內(nèi)存數(shù)據(jù)傳輸,是導(dǎo)致游戲發(fā)熱的主要原因之一。
  2. 延遲、卡頓。像紋理的加載、傳輸都需要耗費時間,另外內(nèi)存資源占用的越多,系統(tǒng)也更加容易觸發(fā) gc 操作,導(dǎo)致游戲非預(yù)期卡頓。
  3. 閃退。游戲超過一定的內(nèi)存上限,操作系統(tǒng)會強制殺死進程。

而紋理占用的內(nèi)存占整個運行內(nèi)存的比重非常大,并且容易做優(yōu)化,所以紋理內(nèi)存占用的大小是需要重點關(guān)注的。


紋理加載流程

下面是一張圖片加載的整個流程。

圖片名稱

可以看出讀取非壓縮紋理與壓縮紋理的主要區(qū)別是: 壓縮紋理不需要解碼 ,數(shù)據(jù)是可以直接被 gpu 讀??;png 等格式圖片,不能直接被 gpu 讀取,需要解碼成未壓縮的位數(shù)據(jù)。不過實際運行中, 并不是所有階段的數(shù)據(jù)都需要保存 。非壓縮紋理在 cpu 內(nèi)存里的編碼數(shù)據(jù)(藍色區(qū)域),在解碼后,是不需要再保存的。


紋理管理方式

下面列舉幾種小游戲開發(fā)可以使用的紋理管理方案:

  1. 將所有資源都加載進 gpu 內(nèi)存,那么對于非壓縮紋理,只需要在 gpu 內(nèi)存保存一份解碼數(shù)據(jù),壓縮紋理只需要在 gpu 內(nèi)存保存一份壓縮紋理數(shù)據(jù)。也就是只需要紅色區(qū)域的部分。
  2. 將所有資源都加載進 cpu 內(nèi)存,然后在運行時,將所需要繪制的資源,加載進 gpu 內(nèi)存,不需要繪制時,可以釋放掉。
  3. 將部分資源加載進 cpu 內(nèi)存,然后在運行時,再將所需要繪制的資源,加載進 gpu 內(nèi)存。根據(jù)需要將資源加載、釋放。

那么這三種方式各有什么優(yōu)缺點呢?

第 1 種方式是運行性能最好的,因為所有的紋理數(shù)據(jù)都在 gpu 內(nèi)存,可以直接繪畫,無需從 cpu 內(nèi)存 copy 數(shù)據(jù),占用的內(nèi)存比較大。但是要求你對 webgl 和所使用的引擎,有一定的了解,保證 gpu 內(nèi)的紋理數(shù)據(jù),沒有被引擎或者自己釋放。游戲引擎在繪制紋理的時候,如果發(fā)現(xiàn) gpu 內(nèi)存中沒有紋理數(shù)據(jù),就會從 cpu 內(nèi)存中尋找數(shù)據(jù)并拷貝。但是由于這種方式,我們沒有在 cpu 內(nèi)存中放置紋理數(shù)據(jù),如果 gpu 中的某些紋理數(shù)據(jù)被釋放了,后面就無法繪制了。如果使用 three.js 這種不自動回收 gpu 資源的引擎,并且整個游戲紋理內(nèi)存占用不大的情況下,可以用這種方法。

第 2 種方式占用的內(nèi)存要比第 1 種方式大,并且性能不如第 1 種方式(如果你提前將需要的紋理加載進 gpu 內(nèi)存,那性能就和 1 一樣了)。大部分引擎會在繪制紋理時,負責(zé)將紋理數(shù)據(jù)從 cpu 內(nèi)存 copy 進 gpu 內(nèi)存,并且管理釋放。如果引擎不釋放資源的話,就需要自己去做。

第 3 種方式的優(yōu)點是,占用的內(nèi)存小,特別適合做多關(guān)卡、多場景游戲。缺點是,需要管理好資源的加載與釋放問題。一般在加載關(guān)卡進度的時候,完成資源的加載。


紋理大小如何計算

要想優(yōu)化紋理占用的內(nèi)存,就要知道如何計算每張紋理的大小。下面用一個例子進行說明。

圖片名稱

上面是臉萌的主場景圖片,jpg 格式,尺寸為 512*512,顏色空間為 RGB888,大小 100kb。解碼后占用的內(nèi)存大小計算公式為:長 * 寬 * 通道個數(shù) * 通道位數(shù),如果解碼成 RGB888 格式,那么占用的內(nèi)存大小為 512*512*3*8bit = 0.75M。而對應(yīng)的 etc2 RGB888 格式的壓縮紋理占用的內(nèi)存大小為 512*512*0.5byte = 0.125M(實際大小為 135kb,因為還包含紋理描述信息)。下面的表格列舉出幾種常用的壓縮紋理格式每像素占用的字節(jié)數(shù)。

圖片名稱


減小紋理占用內(nèi)存的方法

那么減少單張圖片占用的內(nèi)存,有以下幾個方案:

  1. 減小圖片的尺寸,在滿足視覺要求的情況下,盡可能地縮小圖片尺寸,比如將一張 256256 圖片縮小成 128128 尺寸,就減少了 75%的內(nèi)存占用。
  2. 降低通道位數(shù),比如 RGB888 格式的圖片轉(zhuǎn)換為 RGB565 格式。但是這也依賴于具體的解碼方法,現(xiàn)在小游戲引擎,會把圖片資源都解碼成 RGBA8888 格式,那么即使將 RGB888 格式轉(zhuǎn)換為 RGB565 格式,也不會降低解碼后紋理數(shù)據(jù)占用的內(nèi)存。
  3. 使用壓縮紋理,但是有幾個限制點:首先壓縮紋理是有損壓縮,會降低一些圖片質(zhì)量(一般不明顯);其次各個平臺、不同圖形 api 支持的壓縮紋理格式,也不盡相同。比如瀏覽器上可以支持 s3tc 紋理,手機端支持 etc2 紋理(需要支持 opengles3.0),ios 系統(tǒng)支持 pvrtc 紋理。

像 pngquant、tinypng 等采用 color reduction 方法壓縮圖片的工具,能夠減小文件大小,加快加載速度,編碼數(shù)據(jù)占用的內(nèi)存也更小。但是在解碼方式不變的情況下,并不能減小解碼后的圖片內(nèi)存占用大小。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號