硬體加速

Android 2D 算繪管道支援硬體加速功能,也就是說,對畫布執行的所有繪圖作業都使用 GPU。由於啟用硬體加速需要較多資源,應用程式會耗用更多 RAM。

硬體加速功能預設為啟用。如果您的應用程式僅使用標準可組合函式,全域開啟此功能應不會造成不良繪圖效果。不過,由於並非所有 2D 繪圖作業都支援硬體加速,開啟這項設定可能會影響部分自訂繪圖呼叫。通常會出現的問題包括隱形元素、例外狀況或錯誤轉譯像素。為解決上述現象,Android 會讓您在多個層級選擇啟用或停用硬體加速。請參閱「控制硬體加速」。

如果您的應用程式會自訂繪圖,請在開啟硬體加速的實際硬體裝置上測試應用程式,以找出硬體問題。「繪圖作業支援」一節說明硬體加速的已知問題及解決方法。

另請參閱「OpenGL with the Framework APIs」。

控制硬體加速

您可以在下列層級中控制硬體加速:

  • 應用程式
  • 活動
  • 視窗
  • 可組合項目

應用程式層級

在 Android 資訊清單檔案中,將下列屬性新增至 <application> 標記,以便為整個應用程式啟用硬體加速:

<application android:hardwareAccelerated="true" ...>

活動層級

如果全域開啟硬體加速時,您的應用程式無法正常運作,也可以個別控制各項活動。如要在活動層級啟用或停用硬體加速,您可以針對 <activity> 元素使用 android:hardwareAccelerated 屬性。以下範例為整個應用程式啟用硬體加速,但針對一項活動停用此功能:

<application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

視窗層級

如果您需要更精細的控制,可以使用下列程式碼啟用特定視窗的硬體加速功能:

window.setFlags(
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
)

可組合函式層級

在 Compose 中,沒有可停用硬體加速功能的個別可組合函式切換鈕。

如要將可組合函式轉譯至專屬圖層,請使用 Modifier.graphicsLayer。這樣一來,轉換屬性 (例如 alphascaleXscaleYtranslationXtranslationYrotationXrotationYrotationZtransformOrigin) 就能變更,而不必重新執行可組合項的繪圖程式碼。為獲得最佳效能,請一律使用修飾符的 lambda 形式設定這些屬性。

如要明確強制使用螢幕外緩衝區進行進階繪圖作業 (例如圖層內的自訂混合),請使用 CompositingStrategy.Offscreen。詳情請參閱「圖形修飾符」。

如果您有自訂繪圖作業,且嚴格要求軟體算繪,可以使用 AndroidView 代管舊版 View,並在該檢視區塊上呼叫 setLayerType(View.LAYER_TYPE_SOFTWARE, null)

支援繪圖作業

硬體加速時,2D 算繪管道可支援最常用的 Canvas 繪圖作業,以及許多不常用的作業。系統支援所有用於算繪 Android 應用程式的繪圖作業、標準可組合項,以及反射和圖塊紋理等常見的進階視覺效果。

下表說明各種 API 級別的各種作業支援等級:

第一支援的 API 級別
畫布
drawBitmapMesh() (色彩陣列) 18
drawPicture() 23
drawPosText() 16
drawTextOnPath() 16
drawVertices() 29
setDrawFilter() 16
clipPath() 18
clipRegion() 18
clipRect(Region.Op.XOR) 18
clipRect(Region.Op.Difference) 18
clipRect(Region.Op.ReverseDifference) 18
clipRect() 旋轉/視角 18
繪製
setAntiAlias() (適用於文字) 18
setAntiAlias() (行) 16
setFilterBitmap() 17
setLinearText()
setMaskFilter()
setPathEffect() (行) 28
setShadowLayer() (文字除外) 28
setStrokeCap() (行) 18
setStrokeCap() (點) 19
setSubpixelText() 28
Xfermode
PorterDuff.Mode.DARKEN (framebuffer) 28
PorterDuff.Mode.LIGHTEN (framebuffer) 28
PorterDuff.Mode.OVERLAY (framebuffer) 28
著色器
ComposeShader 中的 ComposeShader 28
ComposeShader 中的相同類型著色器 28
ComposeShader 上的本機矩陣 18

畫布縮放

最初的硬體加速 2D 算繪管道最初是支援未縮放的繪圖,有些繪圖作業在採用較大的縮放值時會大幅降低品質。這些作業會實作為縮放比例為 1.0 的紋理,並由 GPU 轉換。從 API 級別 28 開始,所有繪圖作業都可以順利縮放。

下表顯示了變更實作以正確處理大比值縮放:

要縮放的繪圖作業 第一支援的 API 級別
drawText() 18
drawPosText() 28
drawTextOnPath() 28
簡單形狀 17
複雜形狀 28
drawPath() 28
陰影圖層 28

Paint

如果依賴的繪圖作業未經硬體加速,請將受影響的繪圖作業算繪到螢幕外軟體 Bitmap (或 ImageBitmap) 中,然後繪製結果。其餘 UI 則會保留硬體加速路徑。

提示與祕訣

切換為硬體加速 2D 圖像可以立即提升效能,但如果要在設計應用程式時有效使用 GPU,您仍應採用下列建議:

盡量減少版面配置複雜度和重新組合
保持版面配置樹狀結構淺層,並限制重組次數。將狀態讀取作業延後至最窄的範圍,這樣變更時,系統會重新繪製最小的區域。舉例來說,請在 Modifier.graphicsLayer { } 內讀取動畫狀態,而不是在可組合函式的主體中。詳情請參閱「Jetpack Compose 效能」。
避免過度繪製
請勿互相繪製過多圖層。移除檢視畫面上被其他不透明元素完全遮擋的 UI 元素。如果您需要繪製多個彼此重疊的圖層,請考慮將這些圖層合併為單一圖層。使用目前的硬體繪製時,原則上每個畫面每個像素的像素數都不會超過 2.5 倍 (點陣圖數量中的透明像素!)
不要在繪圖方法中建立算繪物件
常見的錯誤是每次叫用算繪方法時,建立新的 Paint 或新的 Path。這會強制更頻繁地執行垃圾收集器,並在硬體管道中略過快取和最佳化。為避免這種情況,請重複使用及變動物件:
  • 使用標準方法:標準 DrawScope 方法 (例如 drawRectdrawCircle) 會在內部重複使用 Paint 物件,不需要開發人員分配。
  • 變動而非重新分配:撰寫自訂邏輯時,請使用 path.rewind 清除現有的 Path,而非例項化新的 Path
  • 有效率地保留狀態:在可組合函式內,使用 remember { Path() } 分配物件一次。如果您要建構可重複使用的自訂修飾符擴充功能,請使用 DrawModifierNode 實作自訂 Modifier.Node,以便分配及重複使用物件,而不會導致新的堆積分配。
不要經常修改形狀
舉例來說,複雜的形狀、路徑和圓形都是使用材質遮罩算繪的。每次建立或修改路徑時,硬體管道都會建立新的遮罩,費用高昂。
不要經常修改點陣圖
每次變更點陣圖的內容時,系統都會在下次繪圖時,重新上傳為 GPU 紋理。
請謹慎使用 Alpha 版
使用 Modifier.alpha 或 Compose Animation API 建立半透明的可組合項時,該項目通常會呈現在螢幕外緩衝區中,所需供應率會加倍。如要避免非重疊內容的螢幕外緩衝區負擔,請設定 CompositingStrategy.ModulateAlpha。如果是個別繪圖呼叫,請直接將 Alpha 套用至繪圖指令 (例如 color = Color.Red.copy(alpha = 0.5f)),不必建立圖層。

其他資源

Views content