Il framework di sincronizzazione descrive esplicitamente le dipendenze tra operazioni asincrone diverse nel sistema grafico Android. Il framework fornisce un'API che consente ai componenti di indicare il rilascio dei buffer. Inoltre, il framework consente il passaggio delle primitive di sincronizzazione tra i driver dal kernel allo spazio utente e tra i vari processi dello spazio utente stessi.
Ad esempio, un'applicazione potrebbe mettere in coda il lavoro da eseguire nella GPU. La GPU inizia a tracciare l'immagine. Anche se l'immagine non è stata disegnata in memoria, il puntatore del buffer viene passato alla finestra con una recinto che indica quando la GPU l'operazione. Il compositore di finestre avvia l'elaborazione in anticipo passa il lavoro al controller del display. In modo simile, la CPU funziona avviene in anticipo. Al termine della GPU, il controller display per visualizzare immediatamente l'immagine.
Il framework di sincronizzazione consente inoltre agli implementatori di sfruttare e le risorse di sincronizzazione nei propri componenti hardware. Infine, offre visibilità sulla pipeline grafica per aiutarti il debug del machine learning.
Sincronizzazione esplicita
La sincronizzazione esplicita consente a produttori e consumer di buffer grafici per segnalare quando ha finito di usare un buffer. La sincronizzazione esplicita è implementato in kernel-space.
I vantaggi della sincronizzazione esplicita includono:
- Minore variazione del comportamento tra i dispositivi
- Miglior supporto al debug
- Metriche di test migliorate
Il framework di sincronizzazione prevede tre tipi di oggetti:
sync_timeline
sync_pt
sync_fence
cronologica_sincronizzazione
sync_timeline
è una sequenza temporale in aumento monotonico che
che i fornitori dovrebbero implementare per ogni istanza del driver, ad esempio un contesto GL,
un controller per il display o un blitter 2D. sync_timeline
conteggi
inviati al kernel per un particolare hardware.
sync_timeline
fornisce garanzie sull'ordine delle operazioni
e consente implementazioni specifiche per l'hardware.
Segui queste linee guida durante l'implementazione di sync_timeline
:
- Fornisci nomi utili per tutti i conducenti, le tempistiche e i recinti per semplificare il debug del machine learning.
- Implementa
timeline_value_str
ept_value_str
operatori nelle sequenze temporali per rendere più leggibile l'output di debug. - Implementa l'
driver_data
di riempimento per fornire librerie dello spazio utente, come la libreria GL, l'accesso ai dati privati della sequenza temporale, se necessario.data_driver
consente ai fornitori di trasmettere informazioni sull'immutabilesync_fence
esync_pts
per creare le righe di comando sulla base di questi ultimi. - Non consentire allo spazio utente di creare o segnalare esplicitamente una recinzione. Esplicitamente la creazione di indicatori/recinzioni porta a un attacco denial of service che interrompe la funzionalità della pipeline.
- Non accedere a
sync_timeline
,sync_pt
osync_fence
in modo esplicito. L'API fornisce tutte le risorse necessarie funzioni.
sincronizzazione_pt
sync_pt
è un singolo valore o punto su una
sync_timeline
. Un punto
ha tre stati: attivo, segnalato e errore. I punti iniziano nello stato attivo
e passare agli stati segnalati o di errore. Ad esempio, quando un'immagine
il consumatore non ha più bisogno di un buffer, viene segnalato un sync_pt
in modo che il produttore di immagini sappia che
è consentito scrivere di nuovo nel buffer.
recinto_sincronizzazione
sync_fence
è una raccolta di valori sync_pt
che spesso
avere sync_timeline
diversi elementi principali (ad esempio, per il display
il controller e la GPU). sync_fence
, sync_pt
e
sync_timeline
sono le primitive principali che driver e spazio utente
per comunicare le loro dipendenze. Quando viene segnalata una recinzione,
inviati prima del limite, poiché
il driver kernel o il blocco hardware esegue i comandi in ordine.
Il framework di sincronizzazione consente a più consumatori o produttori di segnalare
ha finito di utilizzare un buffer, comunicando le informazioni sulle dipendenze con una funzione
. Le barriere sono supportate da un descrittore di file e vengono passate da
dallo spazio kernel allo spazio utente. Ad esempio, una recinzione può contenere due
Valori sync_pt
che indicano il completamento di due consumatori di immagini separati
per leggere un buffer. Quando viene segnalata la recinzione, i produttori di immagini sanno che sia
che i consumatori hanno finito di consumare.
Le barriere, come i valori sync_pt
, iniziano come attive e cambiano stato in base a
lo stato dei loro punti. Se tutti i valori di sync_pt
vengono segnalati, il valore
Viene segnalato il valore sync_fence
. Se un valore di sync_pt
cade
in uno stato di errore, l'intero sync_fence
ha uno stato di errore.
L'appartenenza a un sync_fence
è immutabile una volta che il recinto è
è stato creato. Per ottenere più di un punto in una recinzione, un'unione
condotte in cui i punti di due recinzioni distinte vengono aggiunti a una terza recinzione.
Se uno di questi punti è stato segnalato nella recinzione di origine e l'altro no,
né la terza recinto sarà nello stato segnalato.
Per implementare la sincronizzazione esplicita, fornisci quanto segue:
- Un sottosistema dello spazio del kernel che implementa il framework di sincronizzazione
per un determinato driver hardware. I conducenti che devono essere consapevoli del recinto
in genere qualsiasi elemento che acceda o comunichi con Hardware Composer.
I file chiave includono:
- Implementazione principale:
kernel/common/include/linux/sync.h
kernel/common/drivers/base/sync.c
- Documentazione all'indirizzo
kernel/common/Documentation/sync.txt
- una libreria per comunicare con lo spazio del kernel
platform/system/core/libsync
- Implementazione principale:
- Il fornitore deve fornire l'appropriata
le recinzioni come parametri per
validateDisplay()
epresentDisplay()
nell'HAL. - Due estensioni GL correlate a recinzioni (
EGL_ANDROID_native_fence_sync
eEGL_ANDROID_wait_sync
) e il supporto del recinto nelle immagini conducente.
Case study: implementare un driver display
Per utilizzare l'API che supporta la funzione di sincronizzazione,
sviluppare un driver del display con una funzione di buffer del display. Prima del
framework di sincronizzazione esistente, questa funzione riceverà dma-buf
oggetti, mettere i buffer sul display e bloccarli mentre il buffer era visibile. Per
esempio:
/* * assumes buffer is ready to be displayed. returns when buffer is no longer on * screen. */ void display_buffer(struct dma_buf *buffer);
Con il framework di sincronizzazione, la funzione display_buffer
è più complessa. Quando viene messo sul display un buffer, quest'ultimo viene associato
con una recinzione che indica quando il buffer sarà pronto. Puoi mettere in coda
e iniziare i lavori dopo che il recinto si è risolto.
Mettere in coda e iniziare il lavoro dopo che il recinto è stato cancellato non blocca nulla. Restituisci immediatamente la tua recinzione, il che garantisce che quando il buffer viene disattivata dal display. Quando metti in coda i buffer, il kernel elenca con il framework di sincronizzazione:
/* * 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);
Integrazione della sincronizzazione
Questa sezione spiega come integrare il framework di sincronizzazione dello spazio kernel con le parti dello spazio utente del framework Android e i driver che devono comunicare l'uno con l'altro. Gli oggetti dello spazio del kernel sono rappresentati come descrittori dei file nel tuo spazio utente.
Convenzioni di integrazione
Segui le convenzioni dell'interfaccia di Android HAL:
- Se l'API fornisce un descrittore del file che fa riferimento a un
sync_pt
, il driver del fornitore o l'HAL che utilizza l'API deve chiudere il descrittore del file. - Se il driver del fornitore o l'HAL trasmette un descrittore del file che contiene
un
sync_pt
a una funzione API, il driver del fornitore o l'HAL non deve chiudi il descrittore del file. - Per continuare a utilizzare il descrittore del file di recinto, il driver del fornitore o L'HAL deve duplicare il descrittore.
Un oggetto recinto viene rinominato ogni volta che passa attraverso BufferQueue.
Il supporto della recinzione del kernel consente alle recinzioni di avere stringhe per i nomi, quindi
utilizza il nome della finestra e l'indice del buffer che vengono accodati per
del recinto, ad esempio SurfaceView:0
. Questo
è utile per il debug, al fine di identificare l'origine di un deadlock visualizzato dai nomi.
nell'output di /d/sync
e nelle segnalazioni di bug.
Integrazione di A NativeWindow
A NativeWindow è sensibile al recinto. dequeueBuffer
,
queueBuffer
e cancelBuffer
hanno parametri di recinto.
Integrazione OpenGL ES
L'integrazione della sincronizzazione OpenGL ES si basa su due estensioni EGL:
EGL_ANDROID_native_fence_sync
offre un modo per racchiudere o creare descrittori del file di recinto nativo di Android inEGLSyncKHR
oggetti.EGL_ANDROID_wait_sync
consente i blocchi lato GPU anziché sul lato CPU, facendo in modo che la GPU attendaEGLSyncKHR
. La L'estensioneEGL_ANDROID_wait_sync
è uguale all'estensioneEGL_KHR_wait_sync
.
Per utilizzare queste estensioni in modo indipendente, implementa il metodo
EGL_ANDROID_native_fence_sync
insieme all'estensione associata
il supporto dei kernel. A questo punto, abilita EGL_ANDROID_wait_sync
nel driver. EGL_ANDROID_native_fence_sync
è costituita da un oggetto EGLSyncKHR
di recinto nativo distinto
di testo. Di conseguenza, le estensioni che si applicano ai EGLSyncKHR
esistenti
i tipi di oggetti non si applicano necessariamente a EGL_ANDROID_native_fence
ed evitare interazioni indesiderate.
L'estensione EGL_ANDROID_native_fence_sync
utilizza un modello nativo corrispondente
fence file descriptor, che può essere impostato solo al momento della creazione e
non può essere eseguita direttamente su un oggetto di sincronizzazione esistente. Questo attributo
può essere impostato su una delle due modalità:
- Un descrittore del file di recinto valido aggrega un descrittore nativo esistente
Descrittore di file di recinto Android in un oggetto
EGLSyncKHR
. - -1 crea un descrittore di file di recinto nativo di Android da un
EGLSyncKHR
oggetto.
Utilizza la chiamata di funzione DupNativeFenceFD()
per estrarre
Oggetto EGLSyncKHR
dal descrittore nativo del file di recinto di Android.
Questo risultato corrisponde all'esecuzione di una query sull'attributo set, ma è conforme alle
la convenzione con cui il destinatario chiude il recinto (da qui il duplicato
). Infine, l'eliminazione dell'oggetto EGLSyncKHR
l'attributo recinto interno.
Integrazione di Hardware Composer
Hardware Composer gestisce tre tipi di limiti di sincronizzazione:
- L'opzione Acquisisci le barriere viene passata insieme ai buffer di input
le chiamate
setLayerBuffer
esetClientTarget
. Questi rappresentano una scrittura in sospeso nel buffer e devono essere segnalati prima SurfaceFlinger o HWC tenta di leggere dal buffer associato eseguire composizioni. - Il sblocco di restrizioni viene recuperato dopo la chiamata a
presentDisplay
sta usando la chiamatagetReleaseFences
. Questi rappresentano una lettura in attesa dal buffer precedente sullo stesso livello. R rilascia indicatori del recinto quando l'HWC non utilizza più il buffer precedente perché il buffer attuale ha sostituito quello precedente sul display. Le recinzioni di rilascio vengono restituite all'app insieme ai buffer precedenti che verranno sostituiti durante la composizione corrente. L'app deve attendere fino a quando di rilasciare indicatori del recinto prima di scrivere nel buffer nuovi contenuti che che le è stato restituito. - Le recinzioni presenti vengono restituite, una per frame, nell'ambito di
la chiamata a
presentDisplay
. Gli recinti attuali rappresentano quando composizione di questo frame o, in alternativa, quando il risultato della composizione del frame precedente non è più necessario. Per uso fisico viene visualizzato,presentDisplay
restituisce le barriere presenti quando il frame corrente viene visualizzato sullo schermo. Dopo aver restituito i recinti attuali, puoi scrivere di nuovo nel buffer di destinazione di SurfaceFlinger, se applicabile. Per gli schermi virtuali, le recinzioni presenti vengono restituite quando poter leggere in sicurezza dal buffer di output.