Ich habe viele Texturen im JPG-Format. Und ich muss sie im OpenGL-Speicher laden, bevor die eigentliche Zeichnung beginnt. Ich habe eine Frage gestellt, und mir wurde gesagt, dass die Trennung von JPEG-Entpacken von glTexImage2D (...) -Aufrufen zu einem anderen Thread ist. Das Problem ist, ich bin mir nicht ganz sicher, wie ich das machen soll.
OpenGL (Handler?), benötigt um glTexImage2D auszuführen ist nur in den onSurfaceCreated und OnDrawFrame Methoden von GLSurfaceView.Renderer verfügbar.
Ich kann nicht alle meine Texturen auspacken und dann in onSurfaceCreated (...) in opnegl laden, weil sie wahrscheinlich nicht in den Speicher von limited vm passen (20-40MB?)
Das bedeutet, ich muss sie einzeln entpacken und laden, aber in diesem Fall kann ich keinen opengl-Zeiger bekommen.
Könnte mir bitte jemand ein Beispiel für Threading von Texturen geben, die für OpenGL-Spiele geladen werden?
Es muss ein typisches Verfahren sein, und ich kann nirgendwo etwas finden.
Sie haben nur Ihren Haupt-Thread mit der Upload-Routine, die Zugriff auf OpenGL hat und glTexImage2D aufruft. Der andere Thread lädt (und dekodiert) das Bild von der Datei in den Speicher. Während der sekundäre Thread das nächste Bild lädt, lädt der Haupt-Thread das zuvor geladene Bild in die Textur hoch. Sie benötigen also nur Speicher für zwei Bilder, das aktuell geladene aus der Datei und das aktuell geladene in den GL (welches zuvor geladen wurde). Natürlich brauchen Sie ein wenig Synchronisation, um zu verhindern, dass der Loader-Thread den Speicher überschreibt, den der Haupt-Thread gerade an den GL sendet und um zu verhindern, dass der Haupt-Thread unfertige Daten sendet.
Wie in erklärt, gibt es OpenGLES, die Texturen in anderen Threads laden zwei separate Schritte: Bitmap-Erstellung und Bitmap-Upload. In den meisten Fällen sollten Sie in Ordnung sein, indem Sie einfach die Bitmap-Erstellung in einem sekundären Thread durchführen - was ziemlich einfach ist.
Wenn bei der Frame-Löschung auftritt, rufen Sie texImage2D
von einem Hintergrundthread auf. Dazu müssen Sie einen neuen OpenGL-Kontext erstellen, der seine Texturen mit Ihrem Rendering-Thread teilt, da jeder Thread seinen eigenen OpenGL-Kontext benötigt.
Die Parameter für eglCreateContext
sind etwas kompliziert. Sie müssen setEGLContextFactory
auf Ihrem SurfaceView
verwenden, um sich in die EGLContext-Erstellung einzuloggen:
Dann können Sie einen Textur-Lade-Thread starten:
%Vor%Ich habe eine funktionierende Demonstration der obigen Codeschnipsel in Ссылка erstellt.
Diese Lösung basiert auf vielen Quellen im Internet. Die am meisten beeinflussenden, wo diese drei:
"Es muss eine Möglichkeit geben, GL-Funktionen außerhalb der Initialisierungsfunktion aufzurufen." - Ja. Kopieren Sie einfach den Zeiger auf gl und verwenden Sie es überall.
"Achten Sie darauf, nur OpenGL im Hauptthread zu verwenden." Sehr wichtig. Sie können Ihre Game Engine (die sich in einem anderen Thread befindet) nicht mit einer Textur-Ladefunktion aufrufen, die nicht mit dem gl-Thread synchronisiert ist. Setzen Sie dort ein Flag, um Ihrem gl-thread zu signalisieren, dass es eine neue Textur laden soll (zum Beispiel können Sie eine Funktion in OnDrawFrame (GL gl) platzieren, die prüft, ob eine neue Textur geladen werden muss.)
Hier finden Sie eine Lösung, die eigentlich sehr einfach ist: Nachdem Sie die Bitmap (in einem separaten Thread) geladen haben, speichern Sie sie in einer Instanzvariablen und in draw
method überprüfen Sie, ob sie initialisiert ist, wenn ja, Lade die Textur. Etwas wie das:
Wenn Sie zu Rodjas Antwort hinzufügen möchten, verwenden Sie zum Erstellen des Kontexts Folgendes, wenn Sie einen OpenGL ES 2.0-Kontext erstellen möchten :
%Vor% Sie müssen immer noch setEGLContextClientVersion(2)
aufrufen, da dies auch vom Standard-Konfigurationswähler verwendet wird.
Dies basiert auf Attributliste in eglCreateContext