Kecepatan frame

API frame rate memungkinkan aplikasi memberi tahu platform Android tentang frame rate yang diinginkan dan tersedia di aplikasi yang menargetkan Android 11 (API level 30) atau yang lebih tinggi. Biasanya, sebagian besar perangkat hanya mendukung satu rasio pembaruan tampilan, umumnya 60 Hz, tetapi hal ini telah berubah. Sekarang banyak perangkat mendukung rasio pembaruan lain, seperti 90 Hz atau 120 Hz. Beberapa perangkat mendukung peralihan rasio pembaruan yang lancar, sementara perangkat lain menampilkan layar hitam sebentar, biasanya berlangsung selama satu detik.

Tujuan utama API ini adalah agar aplikasi dapat memanfaatkan semua rasio pembaruan tampilan yang didukung dengan lebih baik. Misalnya, aplikasi yang memutar video 24 Hz yang memanggil setFrameRate() dapat menyebabkan perangkat mengubah rasio pembaruan tampilan dari 60 Hz menjadi 120 Hz. Rasio pembaruan baru ini memungkinkan pemutaran video 24 Hz yang lancar dan tanpa judder, tanpa memerlukan pulldown 3:2 seperti yang diperlukan untuk memutar video yang sama pada tampilan 60 Hz. Ini menghasilkan pengalaman pengguna yang lebih baik.

Penggunaan dasar

Android mengungkapkan beberapa cara untuk mengakses dan mengontrol permukaan, sehingga terdapat beberapa versi setFrameRate() API. Setiap versi API menggunakan parameter yang sama dan berfungsi sama seperti yang lain:

Aplikasi tidak perlu mempertimbangkan rasio pembaruan tampilan yang sebenarnya didukung, yang dapat diperoleh dengan memanggil Display.getSupportedModes(), untuk memanggil setFrameRate() dengan aman. Misalnya, meskipun perangkat hanya mendukung 60 Hz, panggil setFrameRate() dengan frame rate yang disukai aplikasi Anda. Perangkat yang tidak memiliki kecocokan yang lebih baik untuk frame rate aplikasi akan tetap menggunakan rasio pembaruan tampilan saat ini.

Untuk melihat apakah panggilan ke setFrameRate() menghasilkan perubahan pada rasio pembaruan tampilan, daftarkan notifikasi perubahan tampilan dengan memanggilDisplayManager.registerDisplayListener()atau AChoreographer_registerRefreshRateCallback().

Saat memanggil setFrameRate(), sebaiknya teruskan frame rate yang tepat, bukan pembulatan ke bilangan bulat. Misalnya, saat merender video yang direkam pada 29,97 Hz, teruskan 29,97, bukan pembulatan ke 30.

Untuk aplikasi video, parameter kompatibilitas yang diteruskan ke setFrameRate() harus ditetapkan ke Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE untuk memberikan petunjuk tambahan ke platform Android bahwa aplikasi akan menggunakan pulldown untuk beradaptasi dengan rasio pembaruan tampilan yang tidak cocok (yang akan menghasilkan judder).

Dalam beberapa skenario, permukaan video akan berhenti mengirimkan frame, tetapi akan tetap terlihat di layar selama beberapa waktu. Skenario umum mencakup saat pemutaran mencapai akhir video atau saat pengguna menjeda pemutaran. Dalam kasus ini, panggil setFrameRate() dengan parameter frame rate yang ditetapkan ke 0 untuk menghapus setelan frame rate permukaan kembali ke nilai default. Menghapus setelan frame rate seperti ini tidak diperlukan saat menghancurkan permukaan, atau saat permukaan disembunyikan karena pengguna beralih ke aplikasi lain. Hapus setelan frame rate hanya jika permukaan tetap terlihat tanpa digunakan.

Peralihan frame rate yang tidak lancar

Di beberapa perangkat, peralihan rasio pembaruan mungkin mengalami gangguan visual seperti layar hitam selama satu atau dua detik. Hal ini biasanya terjadi pada set top box, panel TV, dan perangkat serupa. Secara default, framework Android tidak beralih mode saat Surface.setFrameRate() API dipanggil, untuk menghindari gangguan visual tersebut.

Beberapa pengguna lebih menyukai gangguan visual di awal dan akhir video yang lebih panjang. Hal ini memungkinkan rasio pembaruan tampilan cocok dengan frame rate video, dan menghindari artefak konversi frame rate seperti judder pulldown 3:2 untuk pemutaran film.

Oleh karena itu, peralihan rasio pembaruan yang tidak lancar dapat diaktifkan jika pengguna dan aplikasi memilih untuk ikut:

Sebaiknya Anda selalu menggunakan CHANGE_FRAME_RATE_ALWAYS untuk video yang berjalan lama seperti film. Hal ini karena manfaat mencocokkan frame rate video lebih besar daripada gangguan yang terjadi saat mengubah rasio pembaruan.

Rekomendasi tambahan

Ikuti rekomendasi ini untuk skenario umum.

Beberapa permukaan

Platform Android didesain untuk menangani skenario dengan benar jika ada beberapa permukaan dengan setelan frame rate yang berbeda. Jika aplikasi Anda memiliki beberapa permukaan dengan frame rate yang berbeda, panggil setFrameRate() dengan frame rate yang benar untuk setiap permukaan. Meskipun perangkat menjalankan beberapa aplikasi sekaligus, menggunakan mode layar terpisah atau picture-in-picture, setiap aplikasi dapat memanggil setFrameRate() dengan aman untuk permukaannya sendiri.

Platform tidak berubah ke frame rate aplikasi

Meskipun perangkat mendukung frame rate yang ditentukan aplikasi dalam panggilan ke setFrameRate(), ada kasus ketika perangkat tidak akan mengalihkan tampilan ke rasio pembaruan tersebut. Misalnya, permukaan prioritas yang lebih tinggi mungkin memiliki setelan frame rate yang berbeda, atau perangkat mungkin dalam mode hemat baterai (menetapkan batasan pada rasio pembaruan tampilan untuk menghemat baterai). Aplikasi harus tetap berfungsi dengan benar saat perangkat tidak mengalihkan rasio pembaruan tampilan ke setelan frame rate aplikasi, meskipun perangkat beralih dalam keadaan normal.

Aplikasi harus memutuskan cara merespons saat rasio pembaruan tampilan tidak cocok dengan frame rate aplikasi. Untuk video, frame rate ditetapkan ke video sumber, dan pulldown akan diperlukan untuk menampilkan konten video. Game mungkin memilih untuk mencoba berjalan pada rasio pembaruan tampilan, bukan tetap menggunakan frame rate yang disukainya. Aplikasi tidak boleh mengubah nilai yang diteruskannya ke setFrameRate() berdasarkan tindakan platform. Aplikasi harus tetap ditetapkan ke frame rate yang disukai, terlepas dari cara aplikasi menangani kasus saat platform tidak menyesuaikan untuk mencocokkan permintaan aplikasi. Dengan begitu, jika kondisi perangkat berubah untuk memungkinkan penggunaan rasio pembaruan tampilan tambahan, platform akan memiliki informasi yang benar untuk beralih ke frame rate yang disukai aplikasi.

Jika aplikasi tidak akan atau tidak dapat berjalan pada rasio pembaruan tampilan, aplikasi harus menentukan stempel waktu presentasi untuk setiap frame, menggunakan salah satu mekanisme platform untuk menetapkan stempel waktu presentasi:

Penggunaan stempel waktu ini akan menghentikan platform menampilkan frame aplikasi terlalu awal, yang akan menghasilkan judder yang tidak perlu. Penggunaan stempel waktu presentasi frame yang benar agak rumit. Untuk game, lihat panduan kecepatan frame kami untuk mengetahui info selengkapnya tentang cara menghindari judder, dan pertimbangkan untuk menggunakan library Android Frame Pacing.

Dalam beberapa kasus, platform dapat beralih ke kelipatan frame rate yang ditentukan aplikasi di setFrameRate(). Misalnya, aplikasi dapat memanggil setFrameRate() dengan 60 Hz dan perangkat dapat mengalihkan tampilan ke 120 Hz. Salah satu alasan hal ini dapat terjadi adalah jika aplikasi lain memiliki permukaan dengan setelan frame rate 24 Hz. Dalam hal ini, menjalankan tampilan pada 120 Hz akan memungkinkan permukaan 60 Hz dan permukaan 24 Hz berjalan tanpa memerlukan pulldown.

Saat tampilan berjalan pada kelipatan frame rate aplikasi, aplikasi harus menentukan stempel waktu presentasi untuk setiap frame guna menghindari judder yang tidak perlu. Untuk game, library Android Frame Pacing berguna untuk menetapkan stempel waktu presentasi frame dengan benar.

setFrameRate() vs preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId adalah cara lain yang dapat digunakan aplikasi untuk menunjukkan frame rate ke platform. Beberapa aplikasi hanya ingin mengubah rasio pembaruan tampilan, bukan mengubah setelan mode tampilan lainnya, seperti resolusi tampilan. Secara umum, gunakan setFrameRate() dan bukan preferredDisplayModeId. Fungsi setFrameRate() lebih mudah digunakan karena aplikasi tidak perlu menelusuri daftar mode tampilan untuk menemukan mode dengan frame rate tertentu.

setFrameRate() memberi platform lebih banyak peluang untuk memilih frame rate yang kompatibel dalam skenario ketika ada beberapa permukaan yang berjalan pada frame rate yang berbeda. Misalnya, pertimbangkan skenario saat dua aplikasi berjalan dalam mode layar terpisah di Pixel 4, dengan satu aplikasi memutar video 24 Hz dan aplikasi lainnya menampilkan daftar yang dapat di-scroll kepada pengguna. Pixel 4 mendukung dua rasio pembaruan tampilan: 60 Hz dan 90 Hz. Dengan menggunakan preferredDisplayModeId API, permukaan video dipaksa untuk memilih 60 Hz atau 90 Hz. Dengan memanggil setFrameRate() dengan 24 Hz, permukaan video memberi platform lebih banyak informasi tentang frame rate video sumber, sehingga platform dapat memilih 90 Hz untuk rasio pembaruan tampilan, yang lebih baik daripada 60 Hz dalam skenario ini.

Namun, ada skenario ketika preferredDisplayModeId harus digunakan, bukan setFrameRate(), seperti berikut:

  • Jika aplikasi ingin mengubah resolusi atau setelan mode tampilan lainnya, gunakan preferredDisplayModeId.
  • Platform hanya akan mengalihkan mode tampilan sebagai respons terhadap panggilan ke setFrameRate() jika peralihan mode ringan dan kemungkinan tidak akan terlihat oleh pengguna. Jika aplikasi lebih suka mengalihkan rasio pembaruan tampilan meskipun memerlukan peralihan mode yang berat (misalnya, di perangkat Android TV), gunakan preferredDisplayModeId.
  • Aplikasi yang tidak dapat menangani tampilan yang berjalan pada kelipatan frame rate aplikasi, yang memerlukan penetapan stempel waktu presentasi pada setiap frame, harus menggunakan preferredDisplayModeId.

setFrameRate() vs preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate menetapkan frame rate pilihan di jendela aplikasi, dan kecepatan berlaku untuk semua permukaan dalam jendela. Aplikasi harus menentukan frame rate yang disukainya, terlepas dari rasio pembaruan yang didukung perangkat, mirip dengan setFrameRate(), untuk memberikan petunjuk yang lebih baik kepada penjadwal tentang frame rate yang diinginkan aplikasi.

preferredRefreshRate diabaikan untuk Surface yang menggunakan setFrameRate(). Secara umum, gunakan setFrameRate() jika memungkinkan.

preferredRefreshRate vs preferredDisplayModeId

Jika aplikasi hanya ingin mengubah rasio pembaruan pilihan, sebaiknya gunakan preferredRefreshRate, bukan preferredDisplayModeId.

Menghindari panggilan setFrameRate() terlalu sering

Meskipun panggilan setFrameRate() tidak terlalu mahal dalam hal performa, aplikasi harus menghindari panggilan setFrameRate() setiap frame atau beberapa kali per detik. Panggilan ke setFrameRate() kemungkinan akan menghasilkan perubahan pada rasio pembaruan tampilan, yang dapat mengakibatkan frame drop selama transisi. Anda harus mengetahui frame rate yang benar terlebih dahulu dan memanggil setFrameRate() sekali.

Penggunaan untuk game atau aplikasi non-video lainnya

Meskipun video adalah kasus penggunaan utama untuk setFrameRate() API, API ini dapat digunakan untuk aplikasi lain. Misalnya, game yang tidak ingin berjalan lebih tinggi dari 60 Hz (untuk mengurangi penggunaan daya dan mencapai sesi bermain yang lebih lama) dapat memanggil Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). Dengan cara ini, perangkat yang berjalan pada 90 Hz secara default akan berjalan pada 60 Hz saat game aktif, yang akan menghindari judder yang akan terjadi jika game berjalan pada 60 Hz saat tampilan berjalan pada 90 Hz.

Penggunaan FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE hanya ditujukan untuk aplikasi video. Untuk penggunaan non-video, gunakan FRAME_RATE_COMPATIBILITY_DEFAULT.

Memilih strategi untuk mengubah frame rate

  • Sebaiknya aplikasi, saat menampilkan video yang berjalan lama seperti film, memanggil setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) dengan fps adalah frame rate video.
  • Sebaiknya aplikasi tidak memanggil setFrameRate() dengan CHANGE_FRAME_RATE_ALWAYS jika Anda memperkirakan pemutaran video akan berlangsung selama beberapa menit atau kurang.

Contoh integrasi untuk aplikasi pemutaran video

Sebaiknya ikuti langkah-langkah berikut untuk mengintegrasikan peralihan rasio pembaruan di aplikasi pemutaran video:

  1. Tentukan changeFrameRateStrategy:
    1. Jika memutar video yang berjalan lama seperti film, gunakan MATCH_CONTENT_FRAMERATE_ALWAYS
    2. Jika memutar video pendek seperti trailer film, gunakan CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
  2. Jika changeFrameRateStrategy adalah CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS , lanjutkan ke langkah 4.
  3. Deteksi apakah peralihan rasio pembaruan yang tidak lancar akan terjadi dengan memeriksa apakah kedua fakta ini benar:
    1. Peralihan mode yang lancar tidak mungkin dilakukan dari rasio pembaruan saat ini (sebut saja C) ke frame rate video (sebut saja V). Hal ini akan terjadi jika C dan V berbeda dan Display.getMode().getAlternativeRefreshRates tidak berisi kelipatan V.
    2. Pengguna telah memilih untuk ikut perubahan rasio pembaruan yang tidak lancar. Anda dapat mendeteksi ini dengan memeriksa apakah DisplayManager.getMatchContentFrameRateUserPreference menampilkan MATCH_CONTENT_FRAMERATE_ALWAYS
  4. Jika peralihan akan lancar, lakukan hal berikut:
    1. Panggil setFrameRate dan teruskan fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, dan changeFrameRateStrategy, dengan fps adalah frame rate video.
    2. Mulai pemutaran video
  5. Jika perubahan mode yang tidak lancar akan terjadi, lakukan hal berikut:
    1. Tampilkan UX untuk memberi tahu pengguna. Perhatikan bahwa sebaiknya Anda menerapkan cara agar pengguna dapat menutup UX ini dan melewati penundaan tambahan di langkah 5.d. Hal ini karena penundaan yang kami rekomendasikan lebih besar dari yang diperlukan pada tampilan yang menunjukkan waktu peralihan yang lebih cepat.
    2. Panggil setFrameRate dan teruskan fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, dan CHANGE_FRAME_RATE_ALWAYS, dengan fps adalah frame rate video.
    3. Tunggu onDisplayChanged callback.
    4. Tunggu 2 detik hingga peralihan mode selesai.
    5. Mulai pemutaran video

Kode semu untuk hanya mendukung peralihan yang lancar adalah sebagai berikut:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
    contentFrameRate,
    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();

Kode semu untuk mendukung peralihan yang lancar dan tidak lancar seperti yang dijelaskan di atas adalah sebagai berikut:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (isSeamlessSwitch(contentFrameRate)) {
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
  transaction.apply();
  beginPlayback();
} else if (displayManager.getMatchContentFrameRateUserPreference()
      == MATCH_CONTENT_FRAMERATE_ALWAYS) {
  showRefreshRateSwitchUI();
  sleep(shortDelaySoUserSeesUi);
  displayManager.registerDisplayListener();
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ALWAYS);
  transaction.apply();
  waitForOnDisplayChanged();
  sleep(twoSeconds);
  hideRefreshRateSwitchUI();
  beginPlayback();
}