Minimize Android GLSurfaceView lag

Nach einigen anderen Fragen zum Stapelüberlauf habe ich die Anleitung zu den Interna von Android-Oberflächen, SurfaceViews usw. gelesen:

https: //source.android.com/devices/graphics/architecture.htm

Dieser Leitfaden hat mir ein viel besseres Verständnis dafür gegeben, wie die verschiedenen Teile auf Android zusammenpassen. Es wird erläutert, wie eglSwapBuffers den gerenderten Frame nur in eine Warteschlange schiebt, die SurfaceFlinger später verwendet, wenn es den nächsten Frame für die Anzeige vorbereitet. Wenn die Warteschlange voll ist, wartet sie, bis ein Puffer für den nächsten Frame verfügbar ist, bevor sie zurückkehrt. Das obige Dokument beschreibt dies als "stopfen der Warteschlange" und sich auf den "Gegendruck" von Swap-Puffern stützen, um das Rendern auf das vsync der Anzeige zu beschränken. Dies geschieht im Standardmodus für kontinuierliches Rendern von GLSurfaceView.

Wenn Ihr Rendering einfach ist und in weniger als der Frame-Periode abgeschlossen ist, ist der negative Effekt eine zusätzliche Verzögerung, die durch die BufferQueue verursacht wird, da das Warten auf SwapBuffers erst dann erfolgt, wenn die Queue voll ist und daher der Frame we Beim Rendern befindet sich das Element immer ganz hinten in der Warteschlange und wird daher beim nächsten vsync-Vorgang nicht sofort angezeigt, da sich wahrscheinlich Puffer in der Warteschlange befinden.

Im Gegensatz dazu tritt Rendering-on-Demand in der Regel viel seltener auf als die Aktualisierungsrate der Anzeige. In der Regel sind die BufferQueues für diese Ansichten leer. Daher werden alle Aktualisierungen, die in diese Warteschlangen verschoben werden, beim nächsten vsync von SurfaceFlinger abgerufen.

Also hier ist die Frage: Wie kann ich einen kontinuierlichen Renderer einrichten, aber mit minimaler Verzögerung? Das Ziel ist, dass die Pufferwarteschlange zu Beginn jeder vsync leer ist. Ich rendere meinen Inhalt in weniger als 16 ms, schiebe ihn in die Warteschlange (Pufferanzahl = 1) und er wird dann von SurfaceFlinger bei der nächsten vsync (Pufferanzahl) verbraucht = 0), wiederholen. Die Anzahl der Puffer in der Warteschlange wird in systrace angezeigt. Das Ziel ist es, diese Zahl zwischen 0 und 1 zu ändern.

Das oben erwähnte Dokument führt Choreographer ein, um Rückrufe bei jedem vsync zu erhalten. Ich bin jedoch nicht davon überzeugt, dass dies ausreicht, um das von mir angestrebte minimale Lag-Verhalten zu erreichen. Ich habe versucht, ein requestRender () auf einem vsync-Rückruf mit einem sehr minimalen onDrawFrame () durchzuführen, und es zeigt tatsächlich das Verhalten der Pufferanzahl 0/1. Was ist jedoch, wenn SurfaceFlinger nicht in der Lage ist, alle seine Aufgaben innerhalb eines einzigen Frame-Zeitraums zu erledigen (möglicherweise wird eine Benachrichtigung eingeblendet oder was auch immer)? In diesem Fall erwarte ich, dass mein Renderer zufriedenstellend 1 Frame pro vsync erzeugt, aber das Consumer-Ende dieser BufferQueue hat einen Frame gelöscht. Ergebnis: Wir wechseln jetzt zwischen 1 und 2 Puffern in unserer Warteschlange und haben eine Verzögerung zwischen dem Rendern und dem Anzeigen des Frames erhalten.

Das Dokument schlägt vor, den Zeitversatz zwischen der gemeldeten vsync-Zeit und dem Zeitpunkt, an dem der Rückruf ausgeführt wird, zu überprüfen. Ich kann sehen, wie das helfen kann, wenn Ihr Rückruf aufgrund Ihres Hauptthreads aufgrund eines Layout-Durchgangs oder etwas Verspätetem zugestellt wird. Allerdings glaube ich nicht, dass SurfaceFlinger dadurch einen Schlag überspringen und keinen Frame verbrauchen kann. Kann die App auf irgendeine Weise feststellen, dass SurfaceFlinger einen Frame gelöscht hat? Es scheint auch so, als ob die Unfähigkeit, die Länge der Warteschlange zu bestimmen, die Idee der Verwendung der vsync-Zeit für Spielstatusaktualisierungen bricht, da sich eine unbekannte Anzahl von Bildern in der Warteschlange befindet, bevor das von Ihnen gerenderte tatsächlich angezeigt wird.

Die maximale Länge der Warteschlange zu verringern und sich auf den Gegendruck zu verlassen, wäre eine Möglichkeit, dies zu erreichen, aber ich glaube nicht, dass es eine API gibt, mit der die maximale Anzahl von Puffern in der GLSurfaceView BufferQueue festgelegt werden kann?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage