Library Frame Pacing Bagian dari Android Game Development Kit.
Library Frame Pacing Android yang juga dikenal sebagai Swappy adalah bagian dari Library AGDK. Ini membantu game OpenGL dan Vulkan menghasilkan rendering yang lancar dan kecepatan frame yang benar di Android. Dokumen ini menentukan kecepatan frame, menjelaskan situasi saat kecepatan frame diperlukan, dan menunjukkan bagaimana library menangani situasi semacam ini. Jika ingin langsung menerapkan kecepatan frame dalam game, lihat Langkah berikutnya.
Latar belakang
Kecepatan frame adalah sinkronisasi loop rendering and logika game dengan subsistem tampilan OS dan hardware tampilan yang mendasarinya. Subsistem tampilan Android didesain untuk menghindari artefak visual (dikenal sebagai tearing) yang dapat terjadi saat hardware tampilan beralih ke frame baru saat proses update. Guna menghindari artefak ini, subsistem tampilan melakukan hal berikut:
- Buffering melewati frame secara internal
- Mendeteksi keterlambatan pengiriman frame
- Mengulangi tampilan frame sebelumnya saat frame terlambat terdeteksi
Sebuah game memberi tahu
SurfaceFlinger,
compositor dalam subsistem tampilan, bahwa game tersebut telah mengirimkan semua panggilan gambar
yang diperlukan untuk frame (dengan memanggil eglSwapBuffers
atau vkQueuePresentKHR
).
SurfaceFlinger memberi sinyal ketersediaan frame ke hardware tampilan menggunakan
kait. Hardware tampilan kemudian menampilkan frame yang diberikan. Hardware tampilan berdetak pada kecepatan konstan, misalnya 60Hz. Jika tidak ada frame baru saat hardware memerlukannya, hardware akan menampilkan kembali frame sebelumnya.
Waktu render frame yang tidak konsisten sering terjadi saat loop render game merender pada kecepatan yang berbeda dengan hardware tampilan native. Jika game yang dijalankan pada kecepatan 30 FPS mencoba merender pada perangkat yang secara native mendukung 60 FPS, loop render game tidak menyadari bahwa frame berulang tetap berada di layar selama 16 milidetik lebih lama. Pemutusan ini biasanya menciptakan inkonsistensi besar pada waktu render frame, seperti: 49 milidetik, 16 milidetik, 33 milidetik. Scene yang terlalu kompleks akan semakin memperparah masalah ini, karena menyebabkan terjadinya frame terlewat.
Solusi yang tidak optimal
Solusi untuk pengaturan kecepatan frame berikut telah digunakan sebelumnya oleh game dan biasanya menghasilkan waktu render frame yang tidak konsisten serta peningkatan latensi input.
Mengirimkan frame secepat yang diizinkan API rendering
Pendekatan ini menghubungkan game ke aktivitas SurfaceFlinger variabel dan memperkenalkan frame latensi tambahan. Pipeline tampilan berisi antrean frame, biasanya berukuran 2, yang terisi jika game mencoba menampilkan frame terlalu cepat. Dengan tidak ada lagi ruang di antrean, loop game (atau setidaknya thread rendering) diblokir oleh panggilan OpenGL atau Vulkan. Game kemudian dipaksa untuk menunggu hardware tampilan untuk menampilkan frame, dan tekanan balik ini akan menyinkronkan kedua komponen. Situasi ini disebut buffer-stuffing atau queue-stuffing. Proses perender tidak menyadari apa yang terjadi, sehingga inkonsistensi kecepatan frame menjadi lebih buruk. Jika game mengambil sampel output sebelum frame, latensi input menjadi lebih buruk.
Menggunakan Android Choreographer dengan sendirinya
Game juga menggunakan Android Choreographer untuk sinkronisasi. Komponen ini, yang tersedia di Java dari API 16 dan di C++ dari API 24, mengirimkan tick reguler pada frekuensi yang sama dengan subsistem tampilan. Masih ada kehalusan tentang kapan tick ini dikirimkan relatif terhadap VSYNC hardware yang sebenarnya, dan offset ini bervariasi menurut perangkat. Buffer-stuffing mungkin masih terjadi untuk frame yang panjang.
Keunggulan library Frame Pacing
Library Frame Pacing menggunakan Android Choreographer untuk sinkronisasi dan menangani variabilitas dalam pengiriman tick untuk Anda. Contoh ini menggunakan stempel waktu presentasi untuk memastikan frame disajikan pada waktu yang tepat dan menyinkronkan fence untuk menghindari buffer stuffing. Library ini menggunakan NDK Choreographer jika tersedia dan beralih kembali ke Java Choreographer jika tidak tersedia.
Library menangani beberapa rasio refresh jika didukung oleh perangkat, sehingga game memiliki fleksibilitas yang lebih besar dalam menampilkan frame. Misalnya, untuk perangkat yang mendukung rasio refresh 60 Hz serta 90 Hz, game yang tidak dapat menghasilkan 60 frame per detik dapat turun ke 45 FPS, bukan 30 FPS, agar tetap lancar. Library ini mendeteksi kecepatan frame game yang diharapkan dan menyesuaikan waktu presentasi frame secara otomatis sebagaimana mestinya. Library Frame Pacing juga meningkatkan daya baterai hidup karena menghindari pembaruan tampilan yang tidak perlu. Misalnya, jika sebuah game rendering pada 60 FPS tetapi layar diperbarui pada 120 Hz, layar diperbarui dua kali untuk setiap {i>frame<i}. Library Frame Pacing menghindari hal ini dengan menetapkan kecepatan refresh ke nilai yang didukung oleh perangkat yang paling dekat dengan target kecepatan frame.
Cara kerjanya
Bagian berikut menunjukkan bagaimana library Frame Pacing menangani frame game yang panjang dan singkat untuk mencapai kecepatan frame yang tepat.
Kecepatan frame yang benar pada 30 Hz
Saat merender pada 30 Hz pada perangkat 60 Hz, situasi ideal di Android ditunjukkan pada gambar 1. SurfaceFlinger mengaitkan buffering grafis baru, jika ada (NB dalam diagram menunjukkan "tidak ada buffering" dan buffering sebelumnya diulang).
Gambar 1. Kecepatan frame ideal pada 30 Hz pada perangkat 60 Hz
Frame game pendek menyebabkan tersendat
Di sebagian besar perangkat modern, mesin game mengandalkan koreografer platform, yang mengirimkan tick untuk mendorong pengiriman frame. Namun, masih ada kemungkinan kecepatan frame yang buruk karena frame pendek, seperti yang terlihat pada gambar 2. Frame pendek yang diikuti oleh frame panjang dianggap oleh pemain sebagai tersendat.
Gambar 2. Frame game pendek C menyebabkan frame B hanya menampilkan satu frame, diikuti dengan beberapa frame C
Library Frame Pacing memecahkan masalah ini dengan menggunakan stempel waktu presentasi. Tujuan
library menggunakan ekstensi stempel waktu presentasi
EGL_ANDROID_presentation_time
dan
VK_GOOGLE_display_timing
sehingga {i>frame<i} tidak disajikan lebih awal, seperti yang terlihat pada gambar 3.
Gambar 3. Frame game B ditampilkan dua kali untuk tampilan yang lebih lancar
Frame panjang menyebabkan tersendat dan latensi
Jika beban kerja tampilan memerlukan waktu lebih lama dari beban kerja aplikasi, frame tambahan akan ditambahkan ke antrean. Hal ini akan menyebabkan, sekali lagi, tersendat dan juga dapat menyebabkan frame latensi tambahan karena terjadi buffer-stuffing (lihat gambar 4). Library ini menghapus ketersendatan dan frame latensi tambahan.
Gambar 4. Frame panjang B memberikan kecepatan yang salah untuk 2 frame — A dan B
Library ini mengatasi masalah ini dengan menggunakan fence sinkronisasi
(EGL_KHR_fence_sync
dan
VkFence
)
untuk menginjeksikan waktu tunggu ke dalam aplikasi yang memungkinkan pipeline tampilan menangkap
naik, daripada membiarkan
tekanan kembali meningkat. Frame A masih menampilkan frame tambahan, tetapi frame B kini menampilkan dengan benar, seperti terlihat pada gambar 5.
Gambar 5. Frame C dan D menunggu ditampilkan
Mode operasi yang didukung
Anda dapat mengonfigurasi library Frame Pacing untuk beroperasi dalam salah satu dari tiga mode berikut:
- Mode otomatis nonaktif + Pipeline
- Mode otomatis aktif + Pipeline
- Mode otomatis aktif + Mode pipeline otomatis (Pipeline/Non-pipeline)
Mode yang direkomendasikan
Anda dapat bereksperimen dengan mode otomatis dan mode pipeline, tetapi Anda memulai dengan menonaktifkannya dan menyertakan hal berikut setelah menginisialisasi Swappy:
swappyAutoSwapInterval(false);
swappyAutoPipelineMode(false);
swappyEnableStats(false);
swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);
Mode pipeline
Untuk mengoordinasikan beban kerja mesin, library biasanya menggunakan model pipeline yang memisahkan beban kerja CPU dan GPU di seluruh batas VSYNC.
Gambar 6. Mode pipeline
Mode non-pipeline
Secara umum, pendekatan ini menghasilkan latensi layar input yang lebih rendah dan lebih dapat diprediksi. Jika game memiliki waktu frame yang sangat rendah, beban kerja CPU dan GPU dapat disesuaikan ke dalam satu interval pertukaran. Dalam hal ini, pendekatan non-pipeline sebenarnya akan menghasilkan latensi layar input yang lebih rendah.
Gambar 7. Mode non-pipeline
Mode otomatis
Sebagian besar game tidak tahu cara memilih interval pertukaran, yang merupakan durasi penyajian setiap frame (misalnya, 33.3 milidetik selama 30 Hz). Di beberapa perangkat, game dapat dirender pada 60 FPS, sementara di perangkat lain mungkin perlu turun ke nilai yang lebih rendah. Mode otomatis mengukur waktu CPU dan GPU untuk melakukan hal berikut:
- Otomatis memilih interval pertukaran: Game yang menampilkan 30 Hz dalam beberapa scene dan 60 Hz di scene lain dapat memungkinkan library menyesuaikan interval ini secara dinamis.
- Menonaktifkan pipeline untuk frame ultracepat: Mengirimkan latensi layar input yang optimal dalam semua kasus.
Beberapa rasio refresh
Perangkat yang mendukung beberapa rasio refresh memberikan fleksibilitas yang lebih tinggi dalam memilih interval pertukaran yang terlihat lancar:
- Pada perangkat 60 Hz: 60 FPS / 30 FPS / 20FPS
- Pada perangkat 60 Hz + 90 Hz: 90 FPS / 60 FPS / 45 FPS / 30 FPS
- Pada perangkat 60 Hz + 90 Hz + 120 Hz: 120 FPS / 90 FPS / 60 FPS / 45 FPS / 40 FPS / 30 FPS
Library memilih rasio refresh yang paling sesuai dengan durasi rendering frame game yang sebenarnya, sehingga memberikan pengalaman visual yang lebih baik.
Untuk informasi selengkapnya tentang kecepatan frame beberapa rasio refresh, lihat postingan blog Rendering rasio refresh tinggi di Android.
Statistik frame
Library Frame Pacing menawarkan statistik berikut untuk keperluan proses debug dan pembuatan profil:
- Histogram jumlah refresh layar yang ditunggu sebuah frame di antrean compositor setelah rendering selesai.
- Histogram jumlah refresh layar yang terjadi antara waktu presentasi yang diminta dan waktu aktual saat ini.
- Histogram jumlah refresh layar yang terjadi antara dua frame berturut-turut.
- Histogram jumlah refresh layar yang terjadi antara awal kerja CPU untuk frame ini dan waktu aktual saat ini.
Langkah berikutnya
Lihat salah satu panduan berikut untuk mengintegrasikan library Android Frame Pacing ke dalam game:
- Mengintegrasikan Android Frame Pacing ke dalam perender OpenGL
- Mengintegrasikan Android Frame Pacing ke dalam perender Vulkan