Frame-Budgetabstufung Teil des Android Game Development Kit.

Die Android Frame Pacing-Bibliothek, auch als Swappy bezeichnet, ist Teil der AGDK Libraries. Er sorgt dafür, dass OpenGL- und Vulkan-Spiele ein flüssiges Rendering die richtige Frame-Taktung für Android. In diesem Dokument wird die Frametaktung definiert, Situationen, in denen Frame-Taktung erforderlich ist, und zeigt, Situationen zu verstehen. Wenn Sie direkt mit der Implementierung der Frame-Taktung in finden Sie unter Nächster Schritt.

Hintergrund

Bei der Frame-Taktung handelt es sich um die Synchronisierung der Logik und Rendering-Schleife eines Spiels mit das Anzeigesubsystem eines Betriebssystems und die zugrunde liegende Displayhardware. Das Android- Das Display-Subsystem wurde entwickelt, um visuelle Störungen zu vermeiden (reißen). kann auftreten, wenn die Display-Hardware teilweise zu einem neuen Frame wechselt. durch ein Update. Um diese Artefakte zu vermeiden, führt das Anzeigesubsystem Folgendes:

  • Führt Frames intern zwischen
  • Erkennt späte Frame-Einreichungen
  • Wiederholt die Anzeige vergangener Frames, wenn späte Frames erkannt werden

Ein Spiel informiert SurfaceFlinger dem Compositor innerhalb des Anzeige-Subsystems, dass er alle Aufrufe, die für einen Frame erforderlich sind (durch Aufrufen von eglSwapBuffers oder vkQueuePresentKHR). SurfaceFlinger signalisiert der Display-Hardware die Verfügbarkeit eines Frames mithilfe eines Verriegelung. Auf der Display-Hardware wird dann der jeweilige Frame angezeigt. Displayhardware mit einer konstanten Rate tickt, z. B. 60 Hz, und wenn es keinen neuen Frame gibt, die Hardware einen Frame benötigt, zeigt sie wieder den vorherigen Frame an.

Uneinheitliche Frame-Times treten häufig auf, wenn eine Spiel-Render-Schleife mit einer als die native Displayhardware. Bei einem Spiel mit 30 fps auf einem Gerät zu rendern, das nativ 60 fps unterstützt, nicht erkennt, dass ein wiederholter Frame für weitere 16 Sekunden auf dem Bildschirm Millisekunden. Diese Verbindung führt in der Regel zu erheblichen Inkonsistenzen im Frame. Mal, z. B. 49 Millisekunden, 16 Millisekunden, 33 Millisekunden. Übermäßig komplexe Szenen verstärken dieses Problem, da sie dazu führen, dass verpasste Frames auftreten.

Nicht optimale Lösungen

Die folgenden Lösungen für die Frame-Taktung wurden in der Vergangenheit bei Spielen Dies führt in der Regel zu inkonsistenten Frame Times und erhöhter Eingabelatenz.

Frames so schnell einreichen, wie es die Rendering-API zulässt

Bei diesem Ansatz wird ein Spiel mit variablen SurfaceFlinger-Aktivitäten verknüpft und ein zusätzlichen Frame an Latenz. Die Anzeige-Pipeline enthält eine Warteschlange mit Frames, in der Regel von Größe 2. Diese Größe füllt sich, wenn im Spiel auch Frames eingeblendet werden sollen. schnell ändern. Da in der Warteschlange kein Platz mehr vorhanden ist, wird die Spielschleife (oder zumindest Rendering-Thread) durch einen OpenGL- oder Vulkan-Aufruf blockiert wird. Das Spiel ist dann warten, bis ein Frame auf der Display-Hardware angezeigt wird, und dieser Gegendruck und synchronisiert die beiden Komponenten. Das wird als Pufferung oder queue-stuffing: Der Renderer-Prozess versteht nicht, was passiert, und verschlimmert die Inkonsistenz der Framerate. Wenn die die Eingabe vor dem Frame, verschlechtert sich die Eingabelatenz.

Android Choreographer allein verwenden

Spiele verwenden außerdem Android Choreographer zur Synchronisierung. Diese Komponente, ab API 16 in Java und ab API 24 in C++ verfügbar, liefert regelmäßige Ticks die gleiche Frequenz wie das Display-Subsystem. Es gibt immer noch Feinheiten wenn dieses Tick relativ zum tatsächlichen Hardware-VSYNC verwendet wird. Offsets variieren je nach Gerät. Bei langen Frames kann es dennoch zu Zwischenspeichern kommen.

Vorteile der Frame Pacing-Bibliothek

Die Frame Pacing-Bibliothek nutzt Android Choreographer zur Synchronisierung und die Schwankungen in den Tick- Angaben für Sie abwickelt. Dabei werden Präsentationen genutzt, Zeitstempel, um sicherzustellen, dass die Frames zum richtigen Zeitpunkt angezeigt werden und die Zäune synchronisiert werden um Puffer zu vermeiden. Die Bibliothek verwendet die NDK Choreographer, sofern verfügbar, und verwendet den Java Choreographer, wenn aber nicht.

Die Bibliothek verarbeitet mehrere Aktualisierungsraten, sofern sie vom Gerät unterstützt werden. wodurch ein Spiel mehr Flexibilität beim Präsentieren eines Frames erhält. Beispiel: Für eine das eine Aktualisierungsrate von 60 Hz sowie eine Aktualisierungsrate von 90 Hz unterstützt. können bei einer Produktion von 60 fps (Bilder pro Sekunde) auf 45 fps statt auf 30 fps sinken. flüssiger machen. Die Mediathek erkennt die erwartete Framerate des Spiels und passt sie automatisch an Präsentationszeiten entsprechend. Die Frame Pacing-Bibliothek verbessert auch die Akkulaufzeit. weil dadurch unnötige Bildschirmupdates vermieden werden. Wenn ein Spiel zum Beispiel das bei 60 fps gerendert wird, aber der Bildschirm mit 120 Hz aktualisiert wird, ist der Bildschirm wird für jeden Frame zweimal aktualisiert. Mit der Frame Pacing-Bibliothek können Sie dies vermeiden, indem Sie Die Aktualisierungsrate auf den Wert, der vom Gerät unterstützt wird, das dem Ziel am nächsten ist Frame-Rate.

Funktionsweise

In den folgenden Abschnitten wird gezeigt, wie die Frame Pacing-Bibliothek mit langen und kurze Spielframes, um das richtige Frame-Tempo zu erreichen.

Korrekte Frametaktung bei 30 Hz

Beim Rendern bei 30 Hz auf einem 60-Hz-Gerät ist die ideale Situation für Android wie in Abbildung 1 dargestellt. SurfaceFlinger speichert neue Grafikpuffer, falls vorhanden (Hinweis in „Kein Zwischenspeicher“, vorhanden und die vorherige wiederholt wird).

Ideale Frame-Taktung bei 30 Hz auf einem 60-Hz-Gerät

Abbildung 1: Ideale Frame-Taktung bei 30 Hz auf einem 60-Hz-Gerät

Kurze Spiel-Frames ruckeln

Auf den meisten modernen Geräten nutzen die Spiel-Engines die Choreografen der Plattform der Bereitstellung von Ticks, um das Senden von Frames zu fördern. Aber es gibt immer noch die Möglichkeit einer schlechten Frametaktung aufgrund kurzer Frames, wie in Abbildung 2 zu sehen. Kurze und dann lange Frames werden vom Player als Ruckeln wahrgenommen.

Frames für kurze Spiele

Abbildung 2: Bei Frame C des kurzen Spiels wird in Frame B nur ein Frame angezeigt. gefolgt von mehreren C-Frames

Die Frame Pacing-Bibliothek löst dieses Problem durch Verwendung von Präsentationszeitstempeln. Die in der Bibliothek die Erweiterungen für Präsentationszeitstempel verwendet, EGL_ANDROID_presentation_time und VK_GOOGLE_display_timing damit die Frames nicht zu früh dargestellt werden, wie in Abbildung 3 dargestellt.

Zeitstempel der Präsentation

Abbildung 3: Spiel-Frame B wird für eine flüssigere Darstellung zweimal präsentiert

Lange Frames führen zu Ruckeln und Latenz

Wenn die Anzeigearbeitslast länger als die Arbeitslast der Anwendung dauert, werden zusätzliche Frames zu einer Warteschlange hinzugefügt. Dies führt wieder zum Ruckeln und kann auch aufgrund von Pufferung zu einem zusätzlichen Frame an Latenz führen (siehe Abbildung 4). Die entfernt das Ruckeln und den zusätzlichen Frame an Latenz.

Frames für lange Spiele

Abbildung 4: Langer Frame B führt zu einer falschen Taktung für 2 Frames – A und B.

Die Bibliothek löst dieses Problem mithilfe von Synchronisierungszäunen. (EGL_KHR_fence_sync und VkFence) um Wartezeiten in die Anwendung einzuschleusen, die es der Anzeige-Pipeline ermöglichen, anstatt einen Gegendruck aufzubauen. Frame A zeigt immer noch ein zusätzlichen Frame, aber Frame B wird jetzt korrekt angezeigt, wie in Abbildung 5 dargestellt.

Wartezeiten, die der Anwendungsebene hinzugefügt wurden

Abbildung 5: Die Frames C und D warten auf die Präsentation

Unterstützte Betriebsmodi

Sie können die Frame Pacing-Bibliothek so konfigurieren, dass sie in einer der drei folgenden Modi:

  • Automatischer Modus aus + Pipeline
  • Automatischer Modus aktiviert + Pipeline
  • Automatischer Modus aktiviert + automatischer Pipelinemodus (Pipeline/Nicht-Pipeline)

Sie können mit dem automatischen Modus und den Pipeline-Modi experimentieren, aber Sie beginnen mit und Folgendes nach der Initialisierung von Swappy einschließen:

  swappyAutoSwapInterval(false);
  swappyAutoPipelineMode(false);
  swappyEnableStats(false);
  swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);

Pipelinemodus

Zur Koordinierung von Engine-Arbeitslasten verwendet die Bibliothek in der Regel ein Pipelining-Modell der die CPU- und GPU-Arbeitslasten über die VSYNC-Grenzen trennt.

Pipelinemodus

Abbildung 6: Pipelinemodus

Nicht-Pipeline-Modus

Im Allgemeinen führt dieser Ansatz zu einem niedrigeren, besser vorhersehbaren Eingabebildschirm. Latenz. In Fällen, in denen die Frame Time eines Spiels sehr niedrig ist, Arbeitslasten passen möglicherweise in ein einzelnes Austauschintervall. In diesem Fall wird eine zu einer geringeren Latenz beim Eingabebildschirm führen.

Nicht-Pipeline-Modus

Abbildung 7: Nicht-Pipeline-Modus

Automatischer Modus

In den meisten Spielen ist nicht bekannt, wie das Tauschintervall ausgewählt wird, also die Dauer in dem jeder Frame dargestellt wird (z. B. 33, 3 ms für 30 Hz). Auf einigen Geräten ein Spiel mit 60 fps rendern kann, während es bei einem anderen Wert. Im automatischen Modus werden CPU- und GPU-Zeiten gemessen, um Folgendes zu tun:

  • Austauschintervalle automatisch auswählen: Spiele, die in einigen Fällen 30 Hz liefern und bei 60 Hz kann die Bibliothek dieses Intervall anpassen. dynamisch aus.
  • Pipeline für extrem schnelle Frames deaktivieren: Hiermit wird das optimale Ergebnis erzielt. Eingabebildschirm-Latenz in allen Fällen.

Mehrere Aktualisierungsraten

Geräte, die mehrere Aktualisierungsraten unterstützen, bieten Ein gleichmäßiges Tauschintervall auswählen:

  • Auf 60-Hz-Geräten: 60 fps / 30 fps / 20 fps
  • Auf Geräten mit 60 Hz + 90 Hz: 90 fps / 60 fps / 45 fps / 30 fps
  • Auf Geräten mit 60 Hz + 90 Hz + 120 Hz: 120 fps / 90 fps / 60 fps / 45 fps 40 fps / 30 fps

Die Bibliothek wählt die Aktualisierungsrate aus, die am besten dem tatsächlichen Rendering entspricht die Dauer der Frames eines Spiels, was ein besseres visuelles Erlebnis ermöglicht.

Weitere Informationen zur Frametaktung mit mehreren Aktualisierungsraten finden Sie in der Hohe Aktualisierungsrate unter Android Blogpost.

Framestatistiken

Die Frame Pacing-Bibliothek bietet die folgenden Statistiken für Debugging und Profilerstellung:

  • Ein Histogramm der Bildschirmanzahl aktualisiert einen im Compositor-Warteschlange nach Abschluss des Renderings.
  • Ein Histogramm der Anzahl von Bildschirmaktualisierungen, die zwischen den angeforderten die Präsentationszeit und die tatsächliche Zeit der Gegenwart.
  • Histogramm der Anzahl von Bildschirmaktualisierungen, die zwischen zwei aufeinanderfolgenden Frames.
  • Ein Histogramm der Anzahl von Bildschirmaktualisierungen, die zwischen dem CPU-Arbeit für diesen Frame und die aktuelle Zeit.

Nächster Schritt

Informationen zum Integrieren der Android Frame Pacing Library finden Sie in einer der folgenden Anleitungen in dein Spiel einbauen: