Texture Compression in JPCT-AE

Started by mech, November 22, 2012, 03:07:47 PM

Previous topic - Next topic

mech

Platform: JPCT-AE (Open GL ES 2.0)

Laut Doku kann man zwischen:

  • 24bpp (RGB888), wird beim laden konvertiert?
  • 16bpp (RGB444), wird beim laden konvertiert?
  • ETC1, Kompression nach dem laden der Textur?
wählen.

1) Wann wird konvertiert (ETC1 vor allem)? Erst beim hochladen zur GPU? Oder kümmert sich der Texture Manager darum? Oder schon der Constructor von Texture?
1.1) Funktioniert ETC1 schon gut?

http://www.jpct.net/jpct-ae/doc/serialized-form.html#com.threed.jpct.Texture
Nachdem laut Dokumentation intern alles mit ints arbeitet:
2) Ist der Speicherverbrauch für 16bpp/ETC1 genauso groß wie für 24bpp?
2.1) Sind Texture Objekte bereits für den TextureManager verwendbar ohne das noch zusätzlich etwas an dem Objekt verändert wird? (würde gerne serialisierte Texturen verwenden)

3) Feature Wunsch: Bitte RGB565 implementieren, Transparenz braucht ich fast nie, außer als Effekt Channel für Shader, würde trotzdem gerne RAM sparen.
(1/3 Speicher weniger ist doch was)

4) Wird beim regenerieren des GLContext nochmals komprimiert? Oder werden die "fertigen" Texturen nur in die GPU geladen?

5) Werden beim regenerieren des GLContext die Texturen die vorher da (in der GPU) waren in die GPU geladen oder nur die dann aktuell benötigt werden?
Stichwort: TextureManager.preWarm(fb) nochmal aufrufen um keine Ruckler zu haben?

6) Kann man im voraus mit einem ETC1 Tool konvertierte Grafiken direkt (und schnell) laden? Ein zusätzlicher Konvertierungsschritt scheint unnötig.

EgonOlsen

Quote from: mech on November 22, 2012, 03:07:47 PM
1) Wann wird konvertiert (ETC1 vor allem)? Erst beim hochladen zur GPU? Oder kümmert sich der Texture Manager darum? Oder schon der Constructor von Texture?
Beim Hochladen wird konvertiert. Die Version im VM-Speicher bleibt immer 32bit, nur die Version, die zur GPU wandert, wird konvertiert.

Quote
1.1) Funktioniert ETC1 schon gut?
Wenn die Hardware es unterstützt, dann schon. Wenn nicht, wird die Einstellung ignoriert.

Quote
2) Ist der Speicherverbrauch für 16bpp/ETC1 genauso groß wie für 24bpp?
Jein. Im VM-Speicher schon, auf der GPU nicht. Den Platz im VM-Speicher kann man aber ebenfalls durch Kompression (compress()) oder den Virtualizer bis auf 0 reduzieren.

Quote
2.1) Sind Texture Objekte bereits für den TextureManager verwendbar ohne das noch zusätzlich etwas an dem Objekt verändert wird? (würde gerne serialisierte Texturen verwenden)
Müsste gehen, wenn die gleich nach dem Laden serialisierst. Ich persönlich seher zwar keinen Sinn dahin, große Bitmaps zu serialisieren, aber ok... ;)

Quote
3) Feature Wunsch: Bitte RGB565 implementieren, Transparenz braucht ich fast nie, außer als Effekt Channel für Shader, würde trotzdem gerne RAM sparen.
(1/3 Speicher weniger ist doch was)
Wenn du den Texture-Konstruktor ohne alpha verwendest, nutzt jPCT RGB5551 statt RGB4444. Ich denke, dass ist gut genug. Das eine Bit macht den Kohl nicht fett, beschneidet aber die Flexibilität im Einsatz der Textur. Zumal ich RGB565 schonmal drin hatte und es leider nicht auf allen Geräten vernünftig lief.

Quote
4) Wird beim regenerieren des GLContext nochmals komprimiert? Oder werden die "fertigen" Texturen nur in die GPU geladen?
Ja, wird nochmals komprimiert.

Quote
5) Werden beim regenerieren des GLContext die Texturen die vorher da (in der GPU) waren in die GPU geladen oder nur die dann aktuell benötigt werden?
Stichwort: TextureManager.preWarm(fb) nochmal aufrufen um keine Ruckler zu haben?
Das Verhalten ist identisch zum ersten Start. Es wird das geladen, was benötigt wird wenn es benötigt wird.

Quote
6) Kann man im voraus mit einem ETC1 Tool konvertierte Grafiken direkt (und schnell) laden? Ein zusätzlicher Konvertierungsschritt scheint unnötig.
Nein, momentan nicht. Es ist angedacht, ebenso wie das Cachen der komprimierten Versionen (eher noch das). Aber bisher ist es nicht umgesetzt. Ich empfinde die nötige Zeit auch als nicht wirklich dramatisch (ok, bei 1024*1024 wird es deutlich, aber wer nutzt das schon auf einem Mobilgerät?), von daher hatte ich da jetzt nicht so den Fokus drauf gehabt.

mech

Danke für die schnelle Antwort.

Quote from: EgonOlsen on November 22, 2012, 08:26:56 PM
Die Version im VM-Speicher bleibt immer 32bit
1) Also ist es egal was ich rein schmeiß, alles wird auf 32 Bit raufkonvertiert (in dem VM Speicher)
Erst beim Upload zur GPU wird dann auf RGBA5551/RGBA8888/ETC1/RGBA4444 konvertiert?

Wow, wenn das so wahr ist tut das weh:
Worst case: 32Bit unkomprimiert vs ETC1

Bei einer 256*256 Textur
262 KB vs 33 KB im RAM (Mipmaps mal außen vor), Verhältnis 1:8

256x256 ist keine so ungewöhnliche Texturgröße wenn man für Tablets und moderne Smartphones entwickelt die in der Gegend von 1280x720 bis 1920x1200 angesiedelt sind.

Praktisch gesehen machen nur jpg mit schwacher Kompression (für Bilder ohne Alpha) und png mit Alphakanal (für Bilder mit Alpha) Sinn um den langsamen Flashspeicher zu umgehen. Autsch.

2) Was verwendest du für compress intern? Wie groß ist der memory peak? ( http://www.jpct.net/wiki/index.php/Reducing_memory_usage#Compress_the_in-memory_copy_of_the_texture_data )

3) Für den Virtualizer sehe ich kaum einen Einsatzzweck wenn ich von dem Flashspeicher (langsam) auf den RAM und dann zurück auf den Flashspeicher (wieder langsam) gehe, das ganze wird dann doppelt so langsam  ;)  beim erstmaligen laden, dafür habe ich nichts im RAM, da wäre eine Referenz auf die ursprüngliche Datei noch geschickter. Einziger Vorteil ist das TextureID usw. erhalten bleiben, richtig?

4) Beim Versuch einen Serializer wie in http://www.jpct.net/forum2/index.php?topic=1790.0 beschrieben zu schreiben bin ich auf folgendes Problem gestoßen:

Folgendes Szenario:
Ein Tool zum Deserialisieren das 3 mal geöffnet wird (nacheinander) und jeweils ein anderes 3D Modell (2 Dateien, einmal mit den normalen UVs und einmal mit den Lightmap UVs) mit zwei Texturen (Normale Farb- und Lightmap Textur) in ein Object3D deserialisert.

Da die Texture ID im 3D Objekt gespeichert wird werden die serialisierten 3D Objekte Probleme mit den Textur IDs haben da sie sich überlappen aber nicht die selbe Textur haben (haben ja wieder eine andere Texture ID wenn ich sie dann alle auf einmal lade, z.B. in einem Spiel).

Oder ist die Texture ID direkt vom Dateinamen abhängig?

Wie kann man dieses Problem lösen?

EgonOlsen


  • Ich denke, man sollte nicht im Vorfeld Probleme erfinden, wo unter Umständen keine sind. Ja, eine 256*256 Textur belegt im VM-Speicher 256KB, wenn man sonst nichts damit anstellt. Du kannst aber eben Kompression im VM-Speicher aktivieren, du kannst den Virtualizer benutzen (ja, das ist langsamer als ohne...aber ich würde den Flashspeicher nicht langsamer reden als er ist) und du kannst auch das Verhalten, dass eine Kopie der Texturdaten im RAM gehalten wird, komplett deaktivieren. Dann musst du beim Kontextwechsel aber selber für einen Reload sorgen. Das ist es eigentlich, was der Virtualizer dir abnehmen soll. Mimaps werden übrigens nicht im VM-Speicher abgelegt.
  • ZIP. Das klappt für manche Texturen gut, für andere weniger. Der Kompressionsgrad entspricht etwa dem von PNG. Der Peak liegt etwa bei komprimierte Größe + entpackte Größe.
  • Ja, die ID bleibt erhalten. Und es braucht weniger Speicher. Und es ist eine Zeile Code statt einem eigenen Texturmanagment. Zur Geschwindigkeit habe ich oben schon was geschrieben. Das muss man selber wissen, ob es einem das Wert ist. Mir ist es das im Allgemeinen.
  • Ich bin nicht sicher, ob ich genau verstanden habe, was du meinst. Also im serialisierten Format werden nicht die Textur-IDs abgelegt, sondern die Namen der Texturen und im Object3D dann eine Referenz in die Liste der Namen. Also quasi eine andere Art von ID. Entsprechend werden die dann beim Laden wieder zugeordnet, wenn eine Textur mit diesem Namen existiert. Beantwortet das die Frage? Wenn nicht, bitte nochmal genauer schreiben, was du meinst... ???

mech

Ok, danke für die Infos.

Laut http://www.jpct.net/jpct-ae/doc/serialized-form.html#com.threed.jpct.Object3D werden nur die TextureIDs innerhalb der deserialisierten form gespeichert.

Jetzt zum Beispiel:
2 Modelle (==> 4 .3ds Dateien und 4 .jpg)


1) Deserializer aufmachen ein Modellpaar und ein Texturenpaar reinladen, die Texture IDs für diese beiden Texturen werden wahrscheinlich 1 und 2 sein
2) Deserialisieren in eine Datei: multimodel1.ser
3) Programm schließen

1) Deserializer aufmachen ein anderes Modellpaar und ein anderes Texturenpaar reinladen, die Texture IDs für diese beiden Texturen werden wahrscheinlich 1 und 2 sein
2) Deserialisieren in eine Datei: multimodel2.ser
3) Programm schließen

Wenn ich jetzt beide Dateien serialisiere (in meiner Android app) und die 4 benötigten Texturen laden will haben diese wahrscheinlich die TextureIDs 1,2,3 und 4
und passen somit nicht zu den vorherigen IDs (die bei beiden Modellen 1 und 2 waren)

Um es auf den Punkt zu bringen wie soll der TexturManager aus den integern wieder auf die passende Textur kommen wenn der Name der Textur nirgendwo gespeichert wird?

EgonOlsen

Doch, das klappt. Weil der DeSerializer ein Mapping zwischen IDs und Namen beim Serialisieren erstellt und das mit in die Datei schreibt. Beim Einlesen mappt er dann von der (alten) ID in der Datei wieder auf den Namen und vom Namen auf die neue ID im TextureManager.