2013-02-23 6 views
34

Ich zeichne einen ziemlich großen Pfad aus meiner Sicht und ich stoße auf einige Leistungsprobleme. Der Pfad ist derzeit 32.000 Punkte lang, aber meine Anwendung sollte auf mindestens 128.000 Punkte skalieren. Ich kann nicht wirklich etwas über die Größe des Pfades tun, da die Datasets gerade so groß sind und ich den ganzen Weg sofort anzeigen und Zoom herein zulassen kann.Zeichenpfade und Hardwarebeschleunigung

Ich benutze ein Nexus 10 Android 4.2 ausführen, bei dem die Hardwarebeschleunigung standardmäßig für Anwendungen aktiviert ist, die sie nicht explizit deaktivieren.

Der Pfad mit dem folgenden Code erzeugt (weggelassen ich einige Setup und andere irrelevante Teile):

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); 
     } 

Und dann in der Methode onDraw() gezogen:

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

ich die Zeit gemessen, nimmt, um meine Sicht mit adb shell dumpsys gfxinfo mit und ohne Hardwarebeschleunigung zu zeichnen, und zu meiner Überraschung ist die Hardwarebeschleunigung viel langsamer:

mit Hardware-Beschleunigung:

enter image description here

ohne Hardware-Beschleunigung:

enter image description here

Die Hardware beschleunigte Version dauert etwa 200-300 ms pro Rahmen, die meisten in der Verfahrensstufe verbracht. Die nicht-beschleunigte Version dauert etwa 50 ms, mit 2/3 in der Ziehstufe und 1/3 in der Prozessstufe.

Offensichtlich ist sogar meine schnellere Version ohne Hardwarebeschleunigung immer noch zu langsam, um 60 fps zu erreichen, oder sogar kaum nutzbar, wenn ich zu größeren Datensätzen übergehe.

Die Idee, den Pfad zu einer Bitmap zu rendern und diese Bitmap dann nur an den Bildschirm anzupassen, ist in meinem Fall ebenfalls problematisch. Ich muss das Zoomen sehr weit auf den Pfad unterstützen, und um das Zoomen ohne Verschlechterung der Pfadqualität zu ermöglichen, müsste ich übergroße Bitmaps des Pfades rendern (und würde wahrscheinlich in Speichergrenzen und die Texturgrößenlimits laufen). Und wenn ich weit heranzoome, müsste ich entweder neuere Bilder von nur Teilen des Pfads erstellen oder einfach nur den Pfad direkt rendern, was wahrscheinlich zu Verzögerungen führen würde, die größer als die Framerate sind, wenn die Leistung immer noch der richtigen entspricht jetzt.

Was ich frage mich, ist jetzt

  • Ist das Zeichnen von Linien/Pfade etwas nur die GPU ist schlecht und man sollte versuchen, nicht zu Hardware beschleunigen, oder bin ich wahrscheinlich etwas falsch zu machen, die die schlechte verursacht Performance?
  • Gibt es etwas, was ich tun kann, um so große Pfade mit akzeptabler Leistung zu zeichnen?
+0

Wie passt OpenGL genau dazu? –

+0

Die Hardwarebeschleunigung verwendet OpenGL, soweit ich es verstehe. Aber ich war mir nicht sicher, welches Tag dort verwendet werden sollte. –

+1

Wie zeichnest du das? Wenn Sie der GPU einen Punkt auf einmal ausgeben, werden Sie wahrscheinlich eine schlechtere Leistung erzielen, aber wenn Sie alles auf einmal parsen, sollten Sie zumindest theoretisch einen Anstieg sehen. – Automatico

Antwort

44

Ist das Zeichnen von Linien/Pfade etwas nur die GPU bei schlecht ist und dass man nicht zu Hardware beschleunigen versuchen sollte, oder bin ich etwas falsch zu machen wahrscheinlich, dass die schlechte Leistung verursacht?

Pfade werden immer mit der CPU gerendert. Wenn die App hardwarebeschleunigt ist, bedeutet das, dass der Renderer zuerst den Pfad mit der CPU in eine Bitmap zeichnet, dann diese Bitmap als Textur auf die GPU lädt und schließlich die Textur auf dem Bildschirm zeichnet.

Linien sind vollständig hardwarebeschleunigt. Anstatt eine Path zu verwenden, empfehle ich in diesem Fall Canvas.drawLines().

Gibt es etwas, was ich tun kann, um so große Pfade mit akzeptabler Leistung zu zeichnen?

Sie sollten entweder Canvas.drawLines() verwenden oder den Pfad selbst in eine Bitmap rendern, die Sie verwalten.

+2

Wie für die Zeichnungspfade manuell in die 'Bitmap' und damit sie über den Bildschirm verschoben werden können, habe ich einfachen Code [hier] (https://github.com/barthand/android-pathbitmap) geschoben. Ich verwendete die gleiche Technik, um solche Pfade auf dem GPU-beschleunigten MapView als Overlay zu zeichnen (wo die übliche GPU-beschleunigte Methode des Zeichnens von Path auf dem Overlay wegen der Textur den 'Formpfad zu groß, um in eine Textur gerendert zu werden 'verursachte) Größenbeschränkung auf der GPU). – barthand

+0

Bei Verwendung von 'Canvas.drawLines (float [], Paint)' mit einem Stapel von Punkten anstelle von mehreren Aufrufen von 'Canvas.drawLine (int. Int, int, int)' mit einem einzigen Punkt wurde die Leistung erheblich gesteigert . – Robert

+0

Gibt es eine offizielle Website oder ein Dokument, das besagt, dass Path CPU verwendet und 'Canvas.drawLines()' Hardwarebeschleunigung verwendet? Ich frage das, weil ich sehr schlechte Leistung hatte, nach Performance-Tipps suchte, aber nichts Sinnvolles gefunden habe, bis ich diese Antwort gelesen habe. – Robert

5

Es scheint, als ob Sie in allgemeinen GPG-Engpass geraten.Werfen Sie einen Blick auf die folgenden Links:

How to make route drawing more efficient

Android canvas path real time performance

Switching from canvas to OpenGL

Vor allem die erste, die den Eindruck erwecken, dass Sie eine Bitmap machen und dass stattdessen ziehen. Es sieht so aus, als könnten Sie eine bessere Leistung erzielen, wenn Sie zu openGL wechseln. Es mag einen magischen Weg geben, die existierende Methode zum Laufen zu bringen, aber das ist mir in diesem Moment nicht bewusst.

Warum sehen Sie das Verhalten, das Sie tun, wahrscheinlich weil Sie alle Daten an die GPU zwischen jeder Zeichnung senden. Sie sollten es auf der GPU zwischenspeichern und stattdessen die Übersetzung verwenden. Die Daten nicht neu erstellen und alles an die GPU senden. Sie sind wahrscheinlich I/O bound, was bedeutet, dass die Übertragungsrate zwischen der CPU und der GPU die Leistung einschränkt. Ich kann nicht 100% sicher sein, basierend auf den Daten, die Sie zur Verfügung gestellt haben, aber das ist meine beste Schätzung. Probieren Sie verschiedene Caching-Techniken aus, hauptsächlich den Png-Cache von Link # 1.

3

Das Zeichnen eines Pfades erfordert mehr als nur das "Erzählen" der GPU, um Linien zu zeichnen. Ein Pfad hat viele Eigenschaften, zum Beispiel, wie Enden von Linien behandelt werden oder dass eine Linie punktiert ist, etwas, das nicht GPU beschleunigt ist. Es gibt wahrscheinlich dann ein anderes hickup, wenn Sie feststellen, dass viele Zeilen, die die Kombination aus CPU und GPU-Beschleunigung langsamer geht. Die oben vorgeschlagene Lösung, um zu canvas.drawLines statt canvs.drawPath zu gehen und zu versuchen, nicht eine ausgefallene Paint Methode zu verwenden, könnte helfen.

Wenn das nicht hilft, können Sie versuchen, eine GLSurfaceView zu verwenden und Linien direkt in das stattdessen zu rendern. Das wird etwas OpenGL ES Wissen beinhalten, aber sollte nicht unglaublich schwer sein und könnte viel effektiver sein.

Verwandte Themen