Ich mache führe gerade ein paar Benchmarks zu Texturkompression durch (die Ergebnisse gibt es später in einem anderen Thread), weil ich mich nach langem Hin und Her der Effizienz meines eigenen Texturformats vergewissern möchte – was eigentlich gar kein Format ist: Ich schreibe die Datenblöcke einfach nur so, wie sie sind, auf die Festplatte und webe die wenigen Informationen, die ich zum Laden brauche, in eine handvoll Buchstaben in der Dateiendung.
Mal drei Gründe, die gegen jedes Texturformat – sei es nun DDS, TGA, BMP, PNG oder sonstwas – sprechen:
- Sie sind zu komplex. Wie viele verschiedene Farbtiefen und Pixelformate benötigt eine durchschnittliche Engine? Fünf, zehn, zwanzig? Ich würde sagen, dass selbst große Projekte selten Bedarf an mehr als zehn haben. Fast alle Bildformate sorgen für einen total Input-Overkill, der dann darin resultiert, dass nur einzelne Variationen des Formats implementiert werden – wie viele Anwendungen unterstützen schon TGA in allen Farbtiefen mit und ohne Lauflängenkodierung, BMP mit Bitmasken oder die >200 Pixelformate, die DDS ermöglicht? Implementiert man sie nicht, hat man jede Menge Müll in seinen Dateien (siehe nächster Punkt) und macht Moddern das Leben zur Hölle; implementiert man sie, explodiert die Code-Basis in unwartbare Dimensionen.
- Ihr Inhalt ist überflüssig oder redundant. In 3D-Engines braucht man fast nie Luxus wie Farbraumverwaltung oder Kommentare der Autoren. Texturen haben immer entweder Gamma 2,2 oder 1 (, was sich zudem aus ihrem Pixelformat ableitet: Unsigned Normalized -> 2,2; Signed Normalized -> 1; Floating-Point -> 1). Da die Seitenlängen fast immer Zweierpotenzen sind, reichen allein die Dateigröße und ein Bruch in der Dateiendung, um die Seitenlänge zu errechnen. Pitch gibt es bei Power-of-Two-Seitenlängen eh nicht. Man könnte sogar so weit gehen und behaupten, dass man alle Formate, die man braucht, durchnummeriert und nur noch die Nummer in die Dateiendung schreibt (was aber selbst mir ein wenig zu radikal (= zu schwer lesbar) wäre) – unter diesem Gesichtspunkt erscheint es fast irrsinnig, hunderte Bytes mit solchen Informationen in den Anfang jeder Textur zu pflanzen.
- Container sind Störer. Was kostet ein 100-Byte-Header tatsächlich?
- Bei Texturen sind die Seitenlängen fast immer Zweierpotenzen, dementsprechend geht auch die Größe der Pixeldaten fast immer glatt in Sektor- oder Seitengrößen auf. Mit einem 100-Byte-Header am Anfang verbraucht die Datei 4 KiB mehr Festplattenspeicher (bzw. eine zusätzliche Seite beim Einblenden in den Hauptspeicher), wovon 3,9 ungenutzt bleiben (je nach Anzahl der Texturen liegen da viele MiB brach). Ein zusätzlicher Sektor bedeutet wieder ein paar Prozent mehr Fragmentierungsrisiko.
- Alignment-Verlust, falls der Header kein Vielfaches von 16 B groß ist – blendet man die Datei in den Hauptspeicher, kann man keine High-Performance-Operationen wie SSE mehr auf die Pixeldaten anwenden. Gilt aber für alle Pixelformate über 2 B, da die CPU zum Lesen nicht-ausgerichteter Daten rund doppelt so lang braucht. (Braucht vielleicht auch der Grafiktreiber länger, die Pixel in eine Textur zu kopieren, wenn die Quelle nicht ausgerichtet ist?)
- Entropie – Header, Line-Markers usw. stehen für Maschinen in keinem erkennbaren Zusammenhang zu den Pixeldaten und brechen ihr Muster. 0,01 % Container-Information in einer Datei sorgen dafür, dass sich die Datei 1 % schlechter komprimieren lässt (lassen zumindest meine Benchmarks vermuten).
Naja, so viel zu meiner Meinung: Alles roh schreiben und ein automatisiertes Tool eine ID in den Dateinamen einweben lassen, die auf das Projekt abgestimmt ist.
Gruß, Ky