2013-02-23 13 views
34

Nella mia vista sto disegnando un percorso piuttosto grande e sto riscontrando alcuni problemi di prestazioni. Il percorso è attualmente lungo 32.000 punti, ma la mia applicazione dovrebbe raggiungere almeno i 128.000 punti. Non posso davvero fare nulla per la dimensione del percorso, poiché i set di dati sono così grandi e ho bisogno di essere in grado di visualizzare l'intero percorso in una sola volta e consentire lo zoom.Percorsi di disegno e accelerazione hardware

Sto usando un Nexus 10 con Android 4.2, che ha l'accelerazione hardware abilitata di default per le applicazioni che non la disabilitano esplicitamente.

Il percorso viene creato con il seguente codice (ho omesso alcune operazioni di configurazione e altre parti irrilevanti):

dataPath.moveTo(0, offset - (float) data[leftLimit]/ scalingFactor); 
     for (int i = leftLimit; i < rightLimit; ++i) { 
      x = (i - leftLimit) * dx; 
      y = offset - (float) data[i]/ scalingFactor; 
      dataPath.lineTo(x, y); 
     } 

E poi elaborato nel metodo onDraw():

canvas.drawColor(Color.WHITE); 
canvas.drawPath(dataPath, linePaint); 

ho misurato il tempo per disegnare la mia vista utilizzando adb shell dumpsys gfxinfo con e senza accelerazione hardware e con mia sorpresa l'accelerazione hardware è molto più lenta:

Con accelerazione hardware:

enter image description here

Senza accelerazione hardware: versione

enter image description here

L'hardware accelerata richiede circa 200-300 ms per frame, più passate in fase di processo. La versione non accelerata richiede circa 50 ms, con 2/3 nella fase di disegno e 1/3 nella fase di elaborazione.

Ovviamente anche la mia versione più veloce senza accelerazione hardware è ancora troppo lenta per raggiungere i 60 fps, o per essere anche appena utilizzabile quando passo a set di dati più grandi.

L'idea di rendere il percorso di una bitmap e quindi solo trasformare quella bitmap per adattarla allo schermo è anche problematica nel mio caso. Devo supportare lo zoom molto lontano sul percorso e, per abilitare lo zoom avanti senza che la qualità del percorso peggiori, dovrei eseguire il rendering di bitmap di grandi dimensioni del percorso (e probabilmente correrò nei limiti di memoria e nei limiti delle dimensioni della trama). E quando si esegue lo zoom in lontananza, dovrei creare immagini più nuove solo di parti del percorso o passare semplicemente al rendering del percorso direttamente, il che probabilmente porterebbe a ritardi maggiori del framerate se la performance è ancora simile a ciò che ho ragione adesso.

Quello che mi chiedo ora è

  • sta disegnando linee/percorsi solo qualcosa la GPU è affatto male e che non si dovrebbe cercare di hardware accelerare, o sono io probabilmente fare qualcosa di sbagliato che causa il cattivo prestazione?
  • C'è qualcosa che posso fare per tracciare percorsi così grandi con prestazioni accettabili?
+0

In che modo OpenGL si adatta perfettamente a questo? –

+0

L'accelerazione hardware utilizza OpenGL, per quanto ho capito. Ma non ero sicuro di quale tag usare lì. –

+1

Come stai disegnando questo? Se tracciate 1 punto alla volta per la GPU, probabilmente otterrete prestazioni peggiori, ma se lo fate a pezzi su tutti dovreste vedere un aumento, almeno in teoria. – Automatico

risposta

44

sta disegnando linee/percorsi solo qualcosa la GPU è affatto male e che uno non si dovrebbe cercare di accelerare l'hardware, o sono probabilmente facendo qualcosa di sbagliato che causa la cattiva performance?

I percorsi vengono sempre visualizzati utilizzando la CPU. Quando l'app ha accelerazione hardware, ciò significa che il renderer prima disegnerà il tuo percorso usando la CPU in una bitmap, quindi caricherà quella bitmap come una trama per la GPU e infine disegnerà la trama sullo schermo.

Le linee sono interamente accelerate da hardware. Invece di usare un Path in questo caso, ti consiglio di utilizzare Canvas.drawLines().

C'è qualcosa che posso fare per disegnare percorsi così grandi con prestazioni accettabili ?

È necessario utilizzare Canvas.drawLines() o eseguire il rendering del percorso in un Bitmap gestito.

+2

Come per i tracciati di disegno manualmente nel 'Bitmap' e permettendo loro di essere spostati lungo lo schermo, ho spinto il codice semplice [qui] (https://github.com/barthand/android-pathbitmap). Ho usato la stessa tecnica per ottenere il disegno di tali percorsi su MapView accelerato dalla GPU come overlay (dove il solito metodo accelerato dalla GPU di disegnare Path sull'overlay stava causando un errore nel percorso di forma troppo grande da renderizzare in una trama) limite di dimensioni sulla GPU). – barthand

+0

Per me, usando 'Canvas.drawLines (float [], Paint)' con un batch di punti, invece di più chiamate a 'Canvas.drawLine (int. Int, int, int)' con un singolo punto, aumentato significativamente le prestazioni . – Robert

+0

Esiste un sito o documento ufficiale che afferma che Path utilizza la CPU e 'Canvas.drawLines()' utilizza l'accelerazione hardware? Lo sto chiedendo perché ho avuto prestazioni pessime, ho cercato suggerimenti per le prestazioni ma non ho trovato nulla di significativo fino a quando non ho letto questa risposta. – Robert

5

Sembra che ci si possa imbattere in un collo di bottiglia generale nella GPU.Date un'occhiata ai seguenti link:

How to make route drawing more efficient

Android canvas path real time performance

Switching from canvas to OpenGL

Soprattutto il primo, che suggeriscono che si effettua una bitmap e disegnare che invece. Sembra che tu possa ottenere prestazioni migliori se passi a openGL. Potrebbe esserci un modo magico per far funzionare il metodo esistente, ma non ne sono al corrente in questo momento.

Perché si sta osservando il comportamento che si è probabilmente perché si inviano tutti i dati alla GPU tra ogni estrazione. Dovresti memorizzarlo nella GPU e usare la traduzione. Non ricreare i dati e inviarli tutti alla GPU. Probabilmente sei I/O bound, il che significa che la velocità di trasmissione tra CPU e GPU è ciò che limita le tue prestazioni. Non posso essere sicuro al 100% di questo sulla base dei dati che hai fornito, ma questa è la mia ipotesi migliore. Prova diverse tecniche di caching, principalmente la png-cache dal link # 1.

3

Disegnare un percorso implica più che "dire" alla GPU di disegnare linee. Un percorso ha molte caratteristiche, ad esempio come vengono trattate le estremità delle linee o che una linea è punteggiata, qualcosa che è non accelerata dalla GPU. Probabilmente c'è quindi un altro hickup quando si incontrano così tante linee che rendono più lenta la combinazione di accelerazione CPU e GPU. La soluzione suggerita sopra per passare a canvas.drawLines anziché a canvs.drawPath e provare a non utilizzare un metodo di fantasia Paint potrebbe essere d'aiuto.

Se ciò non è d'aiuto, puoi provare a utilizzare un GLSurfaceView e renderizzare le linee direttamente in quello. Ciò implicherà alcune conoscenze di OpenGL ES, ma non dovrebbe essere incredibilmente difficile da fare e potrebbe essere molto più efficace.

Problemi correlati