Ho bisogno di fare un processo di sola lettura lato CPU sui dati di telecamera dal vivo (solo dal piano Y) seguito da renderlo sulla GPU. I frame non dovrebbero essere renderizzati fino al completamento dell'elaborazione (quindi non sempre voglio rendere l'ultimo frame dalla fotocamera, solo l'ultimo che il lato CPU ha finito di elaborare). Il rendering è disaccoppiato dall'elaborazione della fotocamera e punta a 60 FPS anche se i fotogrammi della videocamera arrivano a un tasso inferiore.Telecamera Zero-copia Elaborazione e rendering Pipeline su Android
C'è un relativo ma di livello superiore domanda sopra a: Lowest overhead camera to CPU to GPU approach on android
Per descrivere la configurazione corrente in un po 'più in dettaglio: abbiamo un pool di buffer app-laterale per i dati della fotocamera in cui i buffer sono o "libero", "in display" o "display in sospeso". Quando arriva un nuovo frame dalla telecamera, prendiamo un buffer libero, memorizziamo il frame (o un riferimento ad esso se i dati effettivi sono in un pool buffer fornito dal sistema), eseguiamo l'elaborazione e immagazziniamo i risultati nel buffer, quindi impostare il buffer "visualizzazione in sospeso". Nel thread di rendering se c'è un buffer "in attesa di visualizzazione" all'inizio del ciclo di rendering, ci si aggancia a quello "in visualizzazione", invece, si esegue il rendering della telecamera e si esegue il rendering dell'altro contenuto utilizzando le informazioni elaborate calcolate dallo stesso cornice della fotocamera.
Grazie alla risposta di @ fadden sulla domanda collegata sopra ora capisco la funzione "output parallelo" dell'API di Android Camera2 condivide i buffer tra le varie code di output, quindi non dovrebbe comportare alcuna copia sui dati, almeno su Android moderno.
In un commento c'era un suggerimento che potevo bloccare le uscite SurfaceTexture e ImageReader allo stesso tempo e solo "sedermi sul buffer" fino al completamento dell'elaborazione. Sfortunatamente non penso che sia applicabile nel mio caso a causa del rendering disaccoppiato che vogliamo ancora guidare a 60 FPS, e che avrà ancora bisogno di accedere al frame precedente mentre quello nuovo viene elaborato per garantire che le cose non vengano fuori sincrono.
Una soluzione che è venuta in mente è avere SurfaceTextures - uno in ciascuno dei nostri buffer lato app (attualmente ne usiamo 3). Con questo schema, quando otteniamo una nuova cornice per la fotocamera, otterremmo un buffer gratuito dal nostro pool di applicazioni. Quindi chiameremmo acquireLatestImage()
su un ImageReader per ottenere i dati da elaborare e chiamare updateTexImage()
su SurfaceTexture nel buffer gratuito. Al momento del rendering abbiamo solo bisogno di assicurarci che SufaceTexture dal buffer "in display" sia quello associato a GL, e tutto dovrebbe essere sincronizzato il più delle volte (come commentato da @fadden c'è una corsa tra chiamare lo updateTexImage()
e lo acquireLatestImage()
ma quella finestra temporale dovrebbe essere abbastanza piccola da renderla rara, ed è forse dectable e risolvibile comunque usando i timestamp nei buffer).
Rilevo nella documentazione che updateTexImage()
può essere chiamato solo quando il SurfaceTexture è associato a un contesto GL, il che suggerisce che avrò bisogno di un contesto GL nel thread di elaborazione della fotocamera anche in modo che il filo della macchina fotografica può fare updateTexImage()
sul SurfaceTexture nel buffer "libero" mentre il thread di rendering è ancora in grado di eseguire il rendering da SurfaceTexture dal buffer "in display".
Così, alle domande:
- Ti sembra un approccio ragionevole?
- SurfaceTextures è fondamentalmente un involucro leggero attorno al pool di buffer condiviso oppure consuma alcune risorse hardware limitate e deve essere utilizzato con moderazione?
- Le chiamate SurfaceTexture sono tutte abbastanza economiche che l'utilizzo di più sarà ancora una grande vittoria rispetto alla semplice copia dei dati?
- Il piano prevede due thread con distinti contesti GL con un SurfaceTexture diverso associato a ciascuno dei quali è probabile che funzioni o sto chiedendo un mondo di driver dolorosi e con errori?
Sembra abbastanza promettente che ho intenzione di provarlo; ma ho pensato che valesse la pena di essere qui nel caso in cui qualcuno (fondamentalmente @fadden!) fosse a conoscenza di dettagli interni che ho trascurato e che renderebbero questa idea pessima.
Grazie per l'ottima spiegazione, e sembra un approccio praticabile. Probabilmente lo deriderò nel fine settimana. Probabilmente lo metterà su github – tangobravo
Con "i soliti passi per garantire la sincronizzazione" intendi solo che il thread che chiama 'updateTexImage()' deve aver chiamato 'detachFromGLContext()' prima che il thread di rendering provi ad allegarlo per il rendering? Nessuno dei requisiti 'glFinish()' che sarebbero necessari se i contesti fossero impostati per condividere le trame come menzionato nel bug di grafika che hai collegato? – tangobravo
C'è ['getTimestamp()'] (https://developer.android.com/reference/android/media/Image.html#getTimestamp()) su Immagine dall'API 19. Mi aspetto che restituisca lo stesso timestamp come SurfaceTexture ma controlleremo che quando provo l'approccio. – tangobravo