Problemumgehung, um den OpenGL-Kontext zu verlieren, wenn Android pausiert?

40

In der Android-Dokumentation heißt es:

Es gibt Situationen, in denen der EGL-Renderingkontext verloren geht. Dies passiert normalerweise, wenn das Gerät nach dem Einschlafen aufwacht. Wenn der EGL-Kontext verloren geht, werden alle OpenGL-Ressourcen (z. B. Texturen), die diesem Kontext zugeordnet sind, automatisch gelöscht. Damit das Rendern korrekt bleibt, muss ein Renderer alle verlorenen Ressourcen neu erstellen, die er noch benötigt. Die Methode onSurfaceCreated (GL10, EGLConfig) bietet sich hierfür an.

Das erneute Laden aller Texturen im OpenGL-Kontext ist jedoch sowohl eine Belastung als auch eine Belastung für den Benutzer, wenn er die App nach einer Pause erneut betritt. Ich weiß, dass "Angry Birds" dies irgendwie vermeidet. Ich suche nach Vorschlägen, wie ich dasselbe erreichen kann.

Ich arbeite mit dem Android NDK r5 (CrystaX-Version). Ich habe diesen möglichen Hack für das Problem gefunden, aber ich versuche zu vermeiden, eine vollständige benutzerdefinierte SDK-Version zu erstellen .

Nick Gotch
quelle
Das Schlafen und Aufwachen bezieht sich auf das Gerät. Während der Benutzer das Spiel pausiert oder den Vorgang wechselt, sollte der EGL-Kontext verloren gehen.
Ali1S232

Antworten:

22

Replica Island hat eine modifizierte Version von GLSurfaceView, die dieses Problem behebt (und mit früheren Android-Versionen funktioniert). Laut Chris Pruett :

Grundsätzlich habe ich das ursprüngliche GLSurfaceView gehackt, um ein ganz bestimmtes Problem zu lösen: Ich wollte verschiedene Aktivitäten in meiner App aufrufen, ohne meinen gesamten OpenGL-Status zu verlieren. Die wichtigste Änderung bestand darin, das EGLSurface vom EGLContext zu trennen und das erstere in onPause () zu verwerfen, das letztere jedoch beizubehalten, bis der Kontext explizit verloren geht. Die Standardimplementierung von GLSurfaceView (die ich übrigens nicht geschrieben habe) wirft den gesamten GL-Status weg, wenn die Aktivität angehalten wird, und ruft onSurfaceCreated () auf, wenn sie fortgesetzt wird. Das bedeutete, dass das Schließen eines Dialogfelds in meinem Spiel eine Verzögerung verursachte, da alle Texturen neu geladen werden mussten.

Sie sollten das Standard-GLSurfaceView verwenden. Wenn Sie die gleiche Funktionalität haben müssen wie ich, können Sie sich meine ansehen. Aber wenn Sie das tun, was ich getan habe, haben Sie auf einigen Mobilteilen alle möglichen schrecklichen Treiberfehler entdeckt (siehe die sehr langen Kommentare am Ende dieser Datei), und Sie können all dieses Durcheinander vermeiden, indem Sie einfach die Standardversion verwenden.

Bearbeiten: Ich habe gerade festgestellt, dass Sie bereits den Link zu einem ähnlichen Hack gepostet haben. Ich glaube nicht, dass es vor Honeycomb eine integrierte Lösung gibt. Replica Island ist ein beliebtes Spiel, das auf vielen Geräten funktioniert. Vielleicht finden Sie Chris 'Implementierung und Kommentare hilfreich.

Firas Assaad
quelle
1
Nachdem ich verschiedene Ansätze zur Umgehung dieses Problems ausprobiert habe, habe ich beschlossen, dass die beste Lösung darin besteht, die App neu zu codieren, um den Kontext neu zu erstellen. Dies ist ein so verschwenderischer Ansatz, aber es sieht nicht so aus, als gäbe es eine gute Lösung code.google.com/p/android/issues/detail?id=12774
Nick Gotch
9

Ich möchte eine weitere Antwort hinzufügen, die mir vor ein oder zwei Jahren von Chris Pruett (Replica Island, Wind-Up Knight, etc.) übermittelt wurde. Dies ist 2013 besonders nützlich, da setPreserveEglContextOnPause (true) bei 4.3 nicht zu funktionieren scheint. (Daran könnte ich mich irren, aber für mich sieht es im Moment so aus, als ich den zuletzt in 2011 veröffentlichten Spielcode aktualisiere.)

Grundsätzlich besteht der Trick darin, Ihre GLSurfaceView von der Ansichtshierarchie von der onPause () Ihrer Aktivität zu trennen. Da es sich zum Zeitpunkt der Ausführung von onPause () nicht in der Ansichtshierarchie befindet, wird der Kontext nie zerstört.

Die onPause () Ihrer Aktivität sollte also so aussehen:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

Und Sie stellen Ihre GLSurfaceView in der Hierarchie nicht von onResume (), sondern von onWindowFocusChanged () wieder her:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

Beachten Sie, dass Sie niemals onPause () und onResume () des GLSurfaceView aufrufen und dass dies das offizielle SDK GLSurfaceView ist. Es ist keine gehackte alternative Version erforderlich.

Reuben Scratton
quelle
Tatsächlich scheint dieser Ansatz nicht zu funktionieren. Chris Pruett hat es in Kombination mit Unity verwendet. Funktioniert diese Problemumgehung möglicherweise nicht in nativen Projekten? Aber nur das Nichtaufrufen von GLView.onPause () scheint zu funktionieren !? Gibt es andere, die dies bestätigen können?
sjkm
Es hat bei mir für Android 2.2 OpenGl ES 2 funktioniert. Ich bin mir nicht sicher, wie es auf anderen Geräten funktioniert. Ich habe ein LG G2 D802 Telefon. Weiß jemand, ob dies eine allgemeine Lösung ist?
Pixel
7

<rant> Ich habe sehr viel Zeit mit diesem Problem verbracht, ich habe viele verschiedene Lösungen ausprobiert und bis heute hat keine funktioniert. Ich denke, dies ist eine der schrecklichsten Designentscheidungen, die ich je gesehen habe, aber ich komme nicht vom Android-Team wirklich überrascht. </ rant>

Die Lösung besteht also darin, das eglContext-Member nach oben zu verschieben und statisch (global) zu machen, damit es nicht zerstört wird. Sie müssen dann lediglich prüfen, ob es null ist oder nicht, bevor Sie es erneut erstellen.

Bisher scheint diese Lösung für uns zu funktionieren, und es ist uns egal, ob sie auf 2005-Geräten funktioniert.

Stephane Cocquereaumont
quelle
4

Verwenden Sie die Waben-API. Es gibt eine Option, um den OGL-Kontext beizubehalten. Andernfalls müssen Sie Ihren Kontext neu laden. Es ist weder schwierig noch schmerzhaft.

Sie müssen verstehen, dass es zwei Fälle gibt (Android 2.1):

  • Bildschirm Pause: Ihre Anwendung ist immer die erste => Hack verfügbar
  • Anwendungspause: Es gibt eine andere Frontanwendung => Keine Lösung

Hinweis: Alte Android-GPUS unterstützen keine Multi-Kontext. Der OpenGL-Kontext geht also verloren, wenn Sie zu einer anderen Anwendung wechseln => Keine Lösung verfügbar (Sie können hacken, um Ihren Kontext in der Bildschirmpause beizubehalten).

Hinweis 2: Die HoneyComb-Funktion ist setPreserveEGLContextOnPause

Ellis
quelle
1
Ich portiere ein C ++ - Spiel auf das Android-NDK, das den Kontext nicht einfach neu laden kann, so dass es zumindest für mich etwas schwierig ist. Schwierigkeiten beiseite, Texturen Nachladen eine Verzögerung einführen , die auf anderen Geräten nicht vorhanden ist (iPhone, PSP, DS, etc ..) Glad Waben beheben dies zu hören , aber leider müssen wir 2.1+ unterstützen
Nick Gotch
1
Dies beantwortet seine Frage überhaupt nicht.
notlesh
1
Wenn Sie nicht verstehen, können Sie es nicht tun.
Ellis
2

Einige der hier aufgeführten Antworten sind für die frühzeitige Verwendung von OpenGL ES unter Android angemessen. Die ersten GLES-Geräte unterstützten nur einen einzigen Kontext, daher wurde GLSurfaceView so konzipiert, dass der Status aggressiv verworfen wird. GLSurfaceView davon zu überzeugen, etwas anderes zu tun, ist nicht einfach.

Für neuere Versionen von Android (wahrscheinlich alles, was GLES 2.x verwendet) ist die beste Antwort, ein einfaches SurfaceView zu verwenden und Ihre eigene EGL- und Thread-Verwaltung durchzuführen. In Grafika finden Sie mehrere Beispiele für GLES, die mit einer einfachen SurfaceView verwendet werden , einschließlich einer Bibliothek einfacher Klassen zum Erstellen und Löschen von EGL-Kontexten.

Es ist immer noch eine gute Praxis, den Status zu entladen, wenn eine App in den Hintergrund tritt, aber für das Beispiel von Chris Pruett - wo die App noch im Vordergrund stand, aber die Aktivität, die das GLSurfaceView hostet, deaktiviert wurde - gibt es keinen Grund zum Zerreißen den Kontext durchgehen.

verblasst
quelle