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 masa pakai baterai karena menghindari pembaruan tampilan yang tidak perlu. Misalnya, jika game dirender pada 60 FPS, tetapi layar diupdate pada 120 Hz, layar akan diupdate dua kali untuk setiap frame. Library Frame Pacing menghindari hal ini dengan menetapkan kecepatan refresh ke nilai yang didukung oleh perangkat yang paling dekat dengan kecepatan frame target.

Cara kerja

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).

Kecepatan frame ideal pada 30 Hz pada perangkat 60 Hz

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.

Frame game pendek

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. Library menggunakan ekstensi stempel waktu presentasi EGL_ANDROID_presentation_time dan VK_GOOGLE_display_timing sehingga frame tidak ditampilkan lebih awal, seperti terlihat pada gambar 3.

Stempel waktu presentasi

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.

Frame game panjang

Gambar 4. Frame panjang B memberikan kecepatan yang salah untuk 2 frame — A dan B

Library ini mengatasi hal ini dengan menggunakan fence sinkronisasi (EGL_KHR_fence_sync dan VkFence) untuk memasukkan waktu tunggu ke dalam aplikasi yang memungkinkan pipeline tampilan mengejar, bukan membiarkan back press terjadi. Frame A masih menampilkan frame tambahan, tetapi frame B kini menampilkan dengan benar, seperti terlihat pada gambar 5.

Waktu tunggu ditambahkan ke lapisan aplikasi

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)

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.

Mode pipeline

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.

Mode non-pipeline

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: