Kerangka sinkronisasi

Kerangka kerja sinkronisasi secara eksplisit menjelaskan ketergantungan antara berbagai operasi asinkron dalam sistem grafis Android. Kerangka kerja ini menyediakan API yang memungkinkan komponen menunjukkan kapan buffer dilepaskan. Kerangka kerja ini juga memungkinkan sinkronisasi primitif diteruskan antara driver dari kernel ke ruang pengguna dan antar proses ruang pengguna itu sendiri.

Misalnya, suatu aplikasi mungkin mengantri pekerjaan untuk dilakukan di GPU. GPU mulai menggambar gambar itu. Meskipun gambar belum dimasukkan ke dalam memori, penunjuk buffer diteruskan ke kompositor jendela bersama dengan pagar yang menunjukkan kapan pekerjaan GPU akan selesai. Kompositor jendela mulai memproses sebelumnya dan meneruskan pekerjaan ke pengontrol tampilan. Dengan cara yang sama, pekerjaan CPU dilakukan sebelumnya. Setelah GPU selesai, pengontrol tampilan segera menampilkan gambar.

Kerangka kerja sinkronisasi juga memungkinkan pelaksana memanfaatkan sumber daya sinkronisasi di komponen perangkat kerasnya sendiri. Terakhir, kerangka kerja ini memberikan visibilitas ke dalam pipeline grafis untuk membantu proses debug.

Sinkronisasi eksplisit

Sinkronisasi eksplisit memungkinkan produsen dan konsumen buffer grafis memberi sinyal ketika mereka selesai menggunakan buffer. Sinkronisasi eksplisit diimplementasikan di ruang kernel.

Manfaat sinkronisasi eksplisit meliputi:

  • Variasi perilaku antar perangkat lebih sedikit
  • Dukungan debugging yang lebih baik
  • Metrik pengujian yang ditingkatkan

Framework sinkronisasi memiliki tiga tipe objek:

  • sync_timeline
  • sync_pt
  • sync_fence

sinkronisasi_garis waktu

sync_timeline adalah garis waktu yang meningkat secara monoton yang harus diterapkan vendor untuk setiap instance driver, seperti konteks GL, pengontrol tampilan, atau blitter 2D. sync_timeline menghitung pekerjaan yang dikirimkan ke kernel untuk perangkat keras tertentu. sync_timeline memberikan jaminan tentang urutan operasi dan memungkinkan implementasi khusus perangkat keras.

Ikuti panduan berikut saat menerapkan sync_timeline :

  • Berikan nama yang berguna untuk semua driver, garis waktu, dan pagar untuk menyederhanakan proses debug.
  • Terapkan operator timeline_value_str dan pt_value_str di timeline untuk membuat keluaran proses debug lebih mudah dibaca.
  • Terapkan pengisian driver_data untuk memberikan perpustakaan ruang pengguna, seperti perpustakaan GL, akses ke data garis waktu pribadi, jika diinginkan. data_driver memungkinkan vendor menyampaikan informasi tentang sync_fence dan sync_pts yang tidak dapat diubah untuk membuat baris perintah berdasarkan keduanya.
  • Jangan izinkan ruang pengguna untuk secara eksplisit membuat atau memberi sinyal pagar. Membuat sinyal/pagar secara eksplisit menghasilkan serangan penolakan layanan yang menghentikan fungsionalitas saluran pipa.
  • Jangan mengakses elemen sync_timeline , sync_pt , atau sync_fence secara eksplisit. API menyediakan semua fungsi yang diperlukan.

sinkronisasi_pt

sync_pt adalah nilai atau titik tunggal pada sync_timeline . Suatu titik mempunyai tiga keadaan: aktif, diberi sinyal, dan kesalahan. Poin dimulai dalam keadaan aktif dan transisi ke keadaan sinyal atau kesalahan. Misalnya, ketika konsumen gambar tidak lagi memerlukan buffer, sync_pt diberi sinyal sehingga produsen gambar tahu bahwa tidak apa-apa untuk menulis ke buffer lagi.

sinkronisasi_pagar

sync_fence adalah kumpulan nilai sync_pt yang sering kali memiliki induk sync_timeline berbeda (misalnya untuk pengontrol tampilan dan GPU). sync_fence , sync_pt , dan sync_timeline adalah primitif utama yang digunakan driver dan ruang pengguna untuk mengomunikasikan dependensinya. Ketika pagar diberi sinyal, semua perintah yang dikeluarkan sebelum pagar dijamin selesai karena driver kernel atau blok perangkat keras menjalankan perintah secara berurutan.

Kerangka kerja sinkronisasi memungkinkan banyak konsumen atau produsen memberi sinyal ketika mereka selesai menggunakan buffer, mengomunikasikan informasi ketergantungan dengan satu parameter fungsi. Pagar didukung oleh deskriptor file dan diteruskan dari ruang kernel ke ruang pengguna. Misalnya, pagar dapat berisi dua nilai sync_pt yang menandakan ketika dua konsumen gambar terpisah selesai membaca buffer. Ketika pagar diberi isyarat, produsen gambar mengetahui bahwa kedua konsumen sudah selesai mengonsumsi.

Pagar, seperti nilai sync_pt , mulai aktif dan mengubah status berdasarkan status poinnya. Jika semua nilai sync_pt menjadi sinyal, sync_fence menjadi sinyal. Jika salah satu sync_pt berada dalam status kesalahan, seluruh sync_fence memiliki status kesalahan.

Keanggotaan di sync_fence tidak dapat diubah setelah pagar dibuat. Untuk mendapatkan lebih dari satu titik dalam satu pagar, dilakukan penggabungan dimana titik-titik dari dua pagar berbeda ditambahkan ke pagar ketiga. Jika salah satu titik tersebut diberi isyarat di pagar asal dan yang lainnya tidak, pagar ketiga juga tidak akan berada dalam keadaan diberi isyarat.

Untuk menerapkan sinkronisasi eksplisit, berikan hal berikut:

  • Subsistem ruang kernel yang mengimplementasikan kerangka sinkronisasi untuk driver perangkat keras tertentu. Driver yang perlu waspada pada umumnya adalah segala sesuatu yang mengakses atau berkomunikasi dengan Komposer Perangkat Keras. File-file utama meliputi:
    • Implementasi inti:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Dokumentasi di kernel/common/Documentation/sync.txt
    • Perpustakaan untuk berkomunikasi dengan ruang kernel di platform/system/core/libsync
  • Vendor harus menyediakan pagar sinkronisasi yang sesuai sebagai parameter fungsi validateDisplay() dan presentDisplay() di HAL.
  • Dua ekstensi GL terkait pagar ( EGL_ANDROID_native_fence_sync dan EGL_ANDROID_wait_sync ) dan dukungan pagar pada driver grafis.

Studi kasus: Menerapkan driver tampilan

Untuk menggunakan API yang mendukung fungsi sinkronisasi, kembangkan driver tampilan yang memiliki fungsi buffer tampilan. Sebelum kerangka sinkronisasi ada, fungsi ini akan menerima objek dma-buf , menampilkan buffer tersebut, dan memblokir saat buffer terlihat. Misalnya:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

Dengan kerangka sinkronisasi, fungsi display_buffer menjadi lebih kompleks. Saat menampilkan buffer, buffer dikaitkan dengan pagar yang menunjukkan kapan buffer akan siap. Anda dapat mengantri dan memulai pekerjaan setelah pagar dibersihkan.

Mengantri dan memulai pekerjaan setelah pagar dibersihkan tidak menghalangi apa pun. Anda segera mengembalikan pagar Anda sendiri, yang menjamin kapan buffer akan hilang dari tampilan. Saat Anda mengantri buffer, kernel mencantumkan dependensi dengan kerangka sinkronisasi:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

Integrasi sinkronisasi

Bagian ini menjelaskan cara mengintegrasikan kerangka sinkronisasi ruang kernel dengan bagian ruang pengguna kerangka Android dan driver yang harus berkomunikasi satu sama lain. Objek ruang kernel direpresentasikan sebagai deskriptor file di ruang pengguna.

Konvensi integrasi

Ikuti konvensi antarmuka Android HAL:

  • Jika API menyediakan deskriptor file yang merujuk ke sync_pt , driver vendor atau HAL yang menggunakan API harus menutup deskriptor file.
  • Jika driver vendor atau HAL meneruskan deskriptor file yang berisi sync_pt ke fungsi API, driver vendor atau HAL tidak boleh menutup deskriptor file.
  • Untuk terus menggunakan deskriptor file pagar, driver vendor atau HAL harus menduplikasi deskriptor tersebut.

Objek pagar diganti namanya setiap kali melewati BufferQueue. Dukungan pagar kernel memungkinkan pagar memiliki string untuk nama, sehingga kerangka sinkronisasi menggunakan nama jendela dan indeks buffer yang sedang diantri untuk memberi nama pagar, seperti SurfaceView:0 . Hal ini berguna dalam proses debug untuk mengidentifikasi sumber kebuntuan saat nama muncul di keluaran /d/sync dan laporan bug.

Integrasi ANativeWindow

ANativeWindow sadar akan pagar. dequeueBuffer , queueBuffer , dan cancelBuffer memiliki parameter pagar.

Integrasi OpenGL ES

Integrasi sinkronisasi OpenGL ES bergantung pada dua ekstensi EGL:

  • EGL_ANDROID_native_fence_sync menyediakan cara untuk menggabungkan atau membuat deskriptor file pagar Android asli di objek EGLSyncKHR .
  • EGL_ANDROID_wait_sync memungkinkan terhentinya sisi GPU, bukan sisi CPU, sehingga membuat GPU menunggu EGLSyncKHR . Ekstensi EGL_ANDROID_wait_sync sama dengan ekstensi EGL_KHR_wait_sync .

Untuk menggunakan ekstensi ini secara mandiri, terapkan ekstensi EGL_ANDROID_native_fence_sync bersama dengan dukungan kernel terkait. Selanjutnya, aktifkan ekstensi EGL_ANDROID_wait_sync di driver Anda. Ekstensi EGL_ANDROID_native_fence_sync terdiri dari jenis objek pagar asli EGLSyncKHR yang berbeda. Akibatnya, ekstensi yang berlaku untuk tipe objek EGLSyncKHR yang ada belum tentu berlaku untuk objek EGL_ANDROID_native_fence , sehingga menghindari interaksi yang tidak diinginkan.

Ekstensi EGL_ANDROID_native_fence_sync menggunakan atribut deskriptor file pagar asli yang sesuai yang hanya dapat disetel pada waktu pembuatan dan tidak dapat ditanyakan secara langsung dari objek sinkronisasi yang ada. Atribut ini dapat diatur ke salah satu dari dua mode:

  • Deskriptor file pagar yang valid menggabungkan deskriptor file pagar Android asli yang ada dalam objek EGLSyncKHR .
  • -1 membuat deskriptor file pagar Android asli dari objek EGLSyncKHR .

Gunakan panggilan fungsi DupNativeFenceFD() untuk mengekstrak objek EGLSyncKHR dari deskriptor file pagar Android asli. Ini memiliki hasil yang sama dengan menanyakan atribut set, tetapi mematuhi konvensi bahwa penerima menutup pagar (karenanya operasi duplikat). Terakhir, penghancuran objek EGLSyncKHR akan menutup atribut pagar internal.

Integrasi Komposer Perangkat Keras

Komposer Perangkat Keras menangani tiga jenis pagar sinkronisasi:

  • Pagar perolehan diteruskan bersama dengan buffer masukan ke panggilan setLayerBuffer dan setClientTarget . Ini mewakili penulisan yang tertunda ke dalam buffer dan harus memberi sinyal sebelum SurfaceFlinger atau HWC mencoba membaca dari buffer terkait untuk melakukan komposisi.
  • Pagar rilis diambil setelah panggilan ke presentDisplay menggunakan panggilan getReleaseFences . Ini mewakili pembacaan yang tertunda dari buffer sebelumnya pada lapisan yang sama. Pagar pelepas memberi sinyal ketika HWC tidak lagi menggunakan buffer sebelumnya karena buffer saat ini telah menggantikan buffer sebelumnya di layar. Pagar rilis diteruskan kembali ke aplikasi bersama dengan buffer sebelumnya yang akan diganti selama komposisi saat ini. Aplikasi harus menunggu hingga pagar rilis memberi sinyal sebelum menulis konten baru ke dalam buffer yang dikembalikan kepada mereka.
  • Pagar yang ada dikembalikan, satu pagar per frame, sebagai bagian dari panggilan ke presentDisplay . Pagar masa kini melambangkan ketika susunan bingkai ini telah selesai, atau secara bergantian, ketika hasil komposisi bingkai sebelumnya tidak diperlukan lagi. Untuk tampilan fisik, presentDisplay mengembalikan pagar yang ada saat frame saat ini muncul di layar. Setelah pagar yang ada dikembalikan, aman untuk menulis lagi ke buffer target SurfaceFlinger, jika berlaku. Untuk tampilan virtual, pagar yang ada dikembalikan ketika sudah aman untuk dibaca dari buffer keluaran.