Kerangka Sinkronisasi

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

Misalnya, aplikasi mungkin mengantrekan pekerjaan untuk dilakukan di GPU. GPU mulai menggambar gambar itu. Meskipun gambar belum ditarik ke dalam memori, pointer buffer diteruskan ke compositor jendela bersama dengan pagar yang menunjukkan kapan pekerjaan GPU akan selesai. Penggabung 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 dalam komponen perangkat keras mereka sendiri. Terakhir, framework menyediakan visibilitas ke dalam pipeline grafis untuk membantu proses debug.

Sinkronisasi eksplisit

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

Manfaat sinkronisasi eksplisit meliputi:

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

Kerangka kerja sinkronisasi memiliki tiga jenis objek:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline adalah garis waktu yang meningkat secara monoton yang harus diterapkan vendor untuk setiap instans 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 ini saat menerapkan sync_timeline :

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

sync_pt

sync_pt adalah nilai atau titik tunggal pada sync_timeline . Sebuah titik memiliki tiga status: aktif, bersinyal, dan error. Poin dimulai dalam status aktif dan transisi ke status bersinyal atau kesalahan. Misalnya, ketika konsumen gambar tidak lagi membutuhkan buffer, sync_pt diberi sinyal sehingga produser gambar tahu bahwa tidak apa-apa untuk menulis ke buffer lagi.

sinkronisasi_pagar

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

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

Pagar, seperti nilai sync_pt , mulai aktif dan ubah status berdasarkan status poinnya. Jika semua nilai sync_pt menjadi sinyal, sync_fence menjadi sinyal. Jika satu sync_pt mengalami status kesalahan, seluruh sync_fence memiliki status kesalahan.

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

Untuk menerapkan sinkronisasi eksplisit, berikan hal berikut:

  • Subsistem ruang kernel yang mengimplementasikan kerangka kerja sinkronisasi untuk driver perangkat keras tertentu. Driver yang perlu diwaspadai umumnya adalah segala sesuatu yang mengakses atau berkomunikasi dengan Komposer Perangkat Keras. File kunci termasuk:
    • Implementasi inti:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Dokumentasi di kernel/common/Documentation/sync.txt
    • Pustaka untuk berkomunikasi dengan ruang kernel di platform/system/core/libsync
  • Vendor harus menyediakan pagar sinkronisasi yang sesuai sebagai parameter ke validateDisplay() dan presentDisplay() di HAL.
  • Dua ekstensi GL terkait pagar ( EGL_ANDROID_native_fence_sync dan EGL_ANDROID_wait_sync ) dan dukungan pagar di 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 , menempatkan buffer tersebut di layar, dan memblokir saat buffer terlihat. Sebagai contoh:

/*
 * 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 meletakkan buffer di layar, buffer dikaitkan dengan pagar yang menunjukkan kapan buffer akan siap. Anda dapat mengantri dan memulai pekerjaan setelah pagar dibersihkan.

Antrian dan memulai pekerjaan setelah pagar dibersihkan tidak menghalangi apa pun. Anda segera mengembalikan pagar Anda sendiri, yang menjamin saat buffer akan mati 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);

Sinkronkan integrasi

Bagian ini menjelaskan cara mengintegrasikan kerangka sinkronisasi ruang kernel dengan bagian ruang pengguna kerangka kerja 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 melewati 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.

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 antri untuk memberi nama pagar, seperti SurfaceView:0 . Ini berguna dalam debugging untuk mengidentifikasi sumber kebuntuan ketika nama-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 membungkus atau membuat deskriptor file pagar Android asli di objek EGLSyncKHR .
  • EGL_ANDROID_wait_sync memungkinkan GPU-side stall daripada CPU-side, membuat GPU menunggu EGLSyncKHR . Ekstensi EGL_ANDROID_wait_sync sama dengan ekstensi EGL_KHR_wait_sync .

Untuk menggunakan ekstensi ini secara independen, 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 tipe objek EGLSyncKHR pagar asli yang berbeda. Akibatnya, ekstensi yang berlaku untuk jenis objek EGLSyncKHR yang ada tidak selalu berlaku untuk objek EGL_ANDROID_native_fence , menghindari interaksi yang tidak diinginkan.

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

  • Deskriptor file pagar yang valid membungkus 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, menghancurkan objek EGLSyncKHR akan menutup atribut pagar internal.

Integrasi Komposer Perangkat Keras

Komposer Perangkat Keras menangani tiga jenis pagar sinkronisasi:

  • Pagar akuisisi diteruskan bersama dengan buffer input ke panggilan setLayerBuffer dan setClientTarget . Ini mewakili penulisan yang tertunda ke 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 tertunda dari buffer sebelumnya pada lapisan yang sama. Pagar pelepas memberi sinyal saat HWC tidak lagi menggunakan buffer sebelumnya karena buffer saat ini telah menggantikan buffer sebelumnya pada tampilan. Pagar rilis diteruskan kembali ke aplikasi bersama dengan buffer sebelumnya yang akan diganti selama komposisi saat ini. Aplikasi harus menunggu hingga sinyal pagar rilis sebelum menulis konten baru ke dalam buffer yang dikembalikan kepada mereka.
  • Pagar saat ini dikembalikan, satu per bingkai, sebagai bagian dari panggilan ke presentDisplay . Pagar masa kini merepresentasikan bila komposisi rangka ini telah selesai, atau bergantian, bila hasil komposisi rangka sebelumnya tidak diperlukan lagi. Untuk tampilan fisik, presentDisplay mengembalikan pagar saat ini ketika bingkai saat ini muncul di layar. Setelah pagar yang ada dikembalikan, aman untuk menulis ke buffer target SurfaceFlinger lagi, jika berlaku. Untuk tampilan virtual, pagar saat ini dikembalikan saat aman untuk dibaca dari buffer output.