Pipeline rendering 2D Android mendukung akselerasi hardware, yang berarti semua operasi gambar yang dilakukan di kanvas menggunakan GPU. Karena perlu resource yang lebih tinggi untuk mengaktifkan akselerasi hardware, aplikasi Anda akan mengonsumsi lebih banyak RAM.
Akselerasi hardware diaktifkan secara default. Jika aplikasi Anda hanya menggunakan composable standar, mengaktifkannya secara global tidak akan menimbulkan efek gambar yang merugikan. Namun, karena akselerasi hardware tidak didukung untuk semua operasi gambar 2D, mengaktifkannya dapat memengaruhi beberapa panggilan gambar kustom Anda. Masalah biasanya bermanifestasi sebagai elemen tak terlihat, pengecualian, atau piksel yang salah dirender. Untuk mengatasinya, Android menyediakan opsi untuk mengaktifkan atau menonaktifkan akselerasi hardware di beberapa tingkat. Lihat Mengontrol akselerasi hardware.
Jika aplikasi Anda menjalankan gambar kustom, uji aplikasi Anda pada hardware sebenarnya dengan akselerasi hardware diaktifkan untuk menemukan masalah. Bagian Dukungan untuk operasi gambar menjelaskan masalah umum terkait akselerasi hardware dan cara mengatasinya.
Lihat juga OpenGL dengan Framework API.
Mengontrol akselerasi hardware
Anda dapat mengontrol akselerasi hardware di tingkat berikut:
- Aplikasi
- Aktivitas
- Jendela
- Composable
Tingkat aplikasi
Dalam file manifes Android Anda, tambahkan atribut berikut ke tag
<application> untuk mengaktifkan akselerasi hardware di seluruh
aplikasi Anda:
<application android:hardwareAccelerated="true" ...>
Tingkat aktivitas
Jika aplikasi Anda tidak berperilaku sebagaimana mestinya saat akselerasi hardware diaktifkan secara global, Anda juga dapat mengontrolnya untuk aktivitas tertentu. Untuk mengaktifkan atau menonaktifkan akselerasi hardware di tingkat aktivitas, Anda dapat menggunakan atribut android:hardwareAccelerated untuk elemen <activity>. Contoh
berikut mengaktifkan akselerasi hardware untuk keseluruhan aplikasi, tetapi
menonaktifkannya untuk satu aktivitas:
<application android:hardwareAccelerated="true">
<activity ... />
<activity android:hardwareAccelerated="false" />
</application>
Tingkat jendela
Jika memerlukan kontrol yang lebih terperinci, Anda dapat mengaktifkan akselerasi hardware untuk jendela tertentu dengan kode berikut:
window.setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
)
Tingkat composable
Di Compose, tidak ada tombol per-composable untuk menonaktifkan akselerasi hardware.
Untuk merender composable ke dalam lapisannya sendiri, gunakan Modifier.graphicsLayer. Hal ini memungkinkan properti transformasi (seperti alpha, scaleX, scaleY, translationX, translationY, rotationX, rotationY, rotationZ, dan transformOrigin) berubah tanpa menjalankan ulang kode gambar composable. Untuk
performa terbaik, selalu gunakan bentuk lambda pengubah untuk menyetel properti ini.
Untuk secara eksplisit memaksa buffer di luar layar untuk operasi gambar lanjutan, seperti pembauran kustom dalam lapisan, gunakan CompositingStrategy.Offscreen.
Untuk mengetahui informasi selengkapnya, lihat Pengubah grafis.
Jika Anda memiliki operasi gambar kustom yang benar-benar memerlukan rendering software, Anda dapat menghosting View lama menggunakan AndroidView dan memanggil setLayerType(View.LAYER_TYPE_SOFTWARE, null) pada tampilan tersebut.
Dukungan untuk operasi gambar
Jika akselerasi hardware diaktifkan, pipeline rendering 2D mendukung operasi gambar Canvas yang paling umum digunakan, serta banyak operasi lain yang jarang digunakan. Semua
operasi gambar yang digunakan untuk merender aplikasi yang disertakan dengan
Android, composable standar, dan efek visual lanjutan yang umum seperti
pantulan dan tekstur berubin didukung.
Tabel berikut menjelaskan tingkat dukungan berbagai operasi di tingkat API:
| Level API pertama yang didukung | ||||
| Canvas | ||||
| drawBitmapMesh() (array warna) | 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() dengan rotasi/perspektif | 18 | |||
| Paint | ||||
| setAntiAlias() (untuk teks) | 18 | |||
| setAntiAlias() (untuk garis) | 16 | |||
| setFilterBitmap() | 17 | |||
| setLinearText() | ✗ | |||
| setMaskFilter() | ✗ | |||
| setPathEffect() (untuk garis) | 28 | |||
| setShadowLayer() (selain teks) | 28 | |||
| setStrokeCap() (untuk garis) | 18 | |||
| setStrokeCap() (untuk titik) | 19 | |||
| setSubpixelText() | 28 | |||
| Xfermode | ||||
| PorterDuff.Mode.DARKEN (framebuffer) | 28 | |||
| PorterDuff.Mode.LIGHTEN (framebuffer) | 28 | |||
| PorterDuff.Mode.OVERLAY (framebuffer) | 28 | |||
| Shader | ||||
| ComposeShader di dalam ComposeShader | 28 | |||
| Shader jenis yang sama di dalam ComposeShader | 28 | |||
| Matriks lokal di ComposeShader | 18 | |||
Penskalaan kanvas
Pipeline rendering 2D dengan akselerasi hardware mula-mula dibuat untuk mendukung gambar yang tidak diskalakan, karena beberapa operasi gambar mengalami penurunan kualitas secara signifikan pada nilai skala lebih tinggi. Operasi ini diimplementasikan saat tekstur yang digambar pada skala 1.0 diubah oleh GPU. Mulai level API 28, semua operasi gambar dapat diskalakan tanpa masalah.
Tabel berikut menunjukkan kapan implementasi diubah untuk menangani skala besar dengan benar:
| Operasi gambar yang akan diskalakan | Level API pertama yang didukung |
| drawText() | 18 |
| drawPosText() | 28 |
| drawTextOnPath() | 28 |
| Bentuk Sederhana | 17 |
| Bentuk Kompleks | 28 |
| drawPath() | 28 |
| Lapisan bayangan | 28 |
Jika operasi gambar yang Anda andalkan tidak diakselerasi hardware, render gambar yang terpengaruh ke Bitmap (atau ImageBitmap) software di luar layar dan gambar hasilnya. Bagian UI lainnya tetap menggunakan jalur yang diakselerasi hardware.
Tips dan trik
Peralihan ke grafis 2D dengan akselerasi hardware dapat meningkatkan performa dengan seketika, tetapi Anda tetap harus mendesain aplikasi agar menggunakan GPU secara efektif dengan mengikuti rekomendasi berikut:
- Meminimalkan kompleksitas tata letak dan rekomposisi
- Jaga agar pohon tata letak tetap dangkal, dan batasi jumlah rekomposisi. Tunda pembacaan status ke cakupan tersempit, sehingga perubahan menggambar ulang wilayah sekecil mungkin. Misalnya, baca status animasi di dalam
Modifier.graphicsLayer { }, bukan di isi composable. Untuk mengetahui informasi selengkapnya, lihat Performa Jetpack Compose. - Hindari overdraw
- Jangan menggambar terlalu banyak lapisan yang bertumpuk satu di atas yang lain. Hapus elemen UI yang sepenuhnya terhalang oleh elemen buram lainnya di atasnya. Jika Anda perlu menggambar beberapa lapisan yang dipadukan satu di atas yang lain, pertimbangkan untuk menggabungkannya menjadi satu lapisan. Salah satu aturan praktis terkait hardware saat ini adalah jangan menggambar lebih dari 2,5 kali lipat jumlah piksel di layar per frame (piksel transparan dalam jumlah bitmap!).
- Jangan membuat objek render dalam metode gambar
- Kesalahan yang umum adalah membuat
Paintbaru atauPathbaru setiap kali metode rendering dipanggil. Hal ini memaksa pembersih sampah memori untuk berjalan lebih sering dan juga mengabaikan cache dan pengoptimalan di pipeline hardware. Untuk menghindarinya, gunakan kembali dan ubah objek Anda:- Gunakan metode standar: Metode
DrawScopestandar (sepertidrawRectdandrawCircle) sudah menggunakan kembali objekPaintsecara internal tanpa memerlukan alokasi developer. - Lakukan mutasi, bukan mengalokasikan ulang: Saat menulis logika kustom, gunakan
path.rewinduntuk menghapusPathyang ada, bukan membuat instancePathbaru. - Menyimpan status secara efisien: Di dalam composable, alokasikan objek satu kali menggunakan
remember { Path() }. Jika Anda membuat ekstensi pengubah kustom yang dapat digunakan kembali, terapkanModifier.Nodekustom menggunakanDrawModifierNodeuntuk mengalokasikan dan menggunakan kembali objek tanpa menyebabkan alokasi heap baru.
- Gunakan metode standar: Metode
- Jangan terlalu sering mengubah bentuk
- Bentuk, jalur, dan lingkaran yang kompleks, misalnya, dirender menggunakan mask tekstur. Setiap kali Anda membuat atau mengubah jalur, pipeline hardware akan membuat mask baru, dan ini dapat memerlukan banyak biaya.
- Jangan terlalu sering mengubah bitmap
- Setiap kali Anda mengubah konten bitmap, bitmap akan diupload lagi sebagai tekstur GPU saat Anda menggambarnya lagi.
- Gunakan alfa dengan hati-hati
- Saat Anda membuat composable transparan menggunakan
Modifier.alphaatau API animasi Compose, composable tersebut biasanya dirender di buffer luar-layar yang menggandakan rasio pengisian yang diperlukan. Untuk menghindari overhead buffer di luar layar untuk konten yang tidak tumpang-tindih, tetapkanCompositingStrategy.ModulateAlpha. Untuk panggilan gambar individual, terapkan alfa langsung ke perintah gambar (seperti dengancolor = Color.Red.copy(alpha = 0.5f)) tanpa membuat lapisan.