Bild aus komprimierten Texturdaten kann nicht erstellt werden (S3TC)

8

Ich habe versucht, komprimierte Bilder mit S3TC (BC / DXT) Komprimierung in Vulkan zu laden, aber bisher hatte ich nicht viel Glück.

Hier ist, was die Vulkan-Spezifikation über komprimierte Bilder sagt:

Ссылка :

  

Komprimierte Texturbilder, die unter Verwendung der komprimierten S3TC-Bildformate gespeichert sind, werden als eine Sammlung von 4 × 4-Texel-Blöcken dargestellt, wobei jeder Block 64 oder 128 Texel-Daten enthält. Das Bild wird als normales 2D-Rasterbild codiert, in dem jeder 4 × 4-Block als ein einzelnes Pixel behandelt wird.

Ссылка :

  

Bei Bildern, die mit linearen Kacheln erstellt wurden, beschreiben rowPitch, arrayPitch und depthPitch das Layout der Unterressource im linearen Speicher. Bei unkomprimierten Formaten ist rowPitch die Anzahl der Bytes zwischen Texeln mit derselben x-Koordinate in benachbarten Zeilen (y-Koordinaten unterscheiden sich um eins). arrayPitch ist die Anzahl der Bytes zwischen Texeln mit derselben x- und y-Koordinate in benachbarten Array-Schichten des Bildes (Array-Layer-Werte unterscheiden sich um eins). depthPitch ist die Anzahl der Bytes zwischen Texeln mit derselben x- und y-Koordinate in benachbarten Schichten eines 3D-Bildes (z-Koordinaten unterscheiden sich um eins). Ausgedrückt als Adressierungsformel hat das Startbyte eines Texels in der Unterresource die Adresse:

     
    

// (x, y, z, Ebene) sind in Texel-Koordinaten

         

Adresse (x, y, z, Ebene) = Ebene ArrayPitch + z TiefePitch + y ReihePitch + x TexelSize + Offset

  
     

Bei komprimierten Formaten ist rowPitch die Anzahl der Bytes zwischen komprimierten Blöcken in benachbarten Zeilen. arrayPitch ist die Anzahl der Bytes zwischen Blöcken in benachbarten Array-Layern. depthPitch ist die Anzahl der Bytes zwischen Blöcken in benachbarten Schichten eines 3D-Bildes.

     
    

// (x, y, z, Ebene) sind in Blockkoordinaten

         

Adresse (x, y, z, Ebene) = Ebene ArrayPitch + z TiefePitch + y ReihePitch + x Blockgröße + Offset;

  
     

arrayPitch ist für Bilder, die nicht als Arrays erstellt wurden, undefiniert. depthPitch ist nur für 3D-Bilder definiert.

     

Bei Farbformaten muss das Element aspectMask von VkImageSubresource VK_IMAGE_ASPECT_COLOR_BIT sein. Für Tiefen- / Schablonenformate muss aspect entweder VK_IMAGE_ASPECT_DEPTH_BIT oder VK_IMAGE_ASPECT_STENCIL_BIT sein. Bei Implementierungen, die Tiefen- und Schablonenaspekte separat speichern, gibt die Abfrage jedes dieser Unterressourcenlayouts einen anderen Offset und eine andere Größe zurück, die den für diesen Aspekt verwendeten Speicherbereich darstellt. Bei Implementierungen, die verschachtelte Tiefen- und Schablonenaspekte speichern, werden derselbe Offset und dieselbe Größe zurückgegeben und die verschachtelte Speicherzuweisung dargestellt.

Mein Bild ist ein normales 2D-Bild (0 Ebenen, 1 Mipmap), also gibt es kein arrayPitch oder depthPitch . Da die S3TC-Komprimierung direkt von der Hardware unterstützt wird, sollte es möglich sein, die Bilddaten zu verwenden, ohne sie vorher zu dekomprimieren. In OpenGL kann dies mit glCompressedTexImage2D gemacht werden, und das hat für mich in der Vergangenheit funktioniert.

In OpenGL habe ich GL_COMPRESSED_RGBA_S3TC_DXT1_EXT als Bildformat verwendet, für Vulkan verwende ich VK_FORMAT_BC1_RGBA_UNORM_BLOCK, was äquivalent sein sollte. Hier ist mein Code für die Zuordnung der Bilddaten:

%Vor%

Und hier ist der Code zum Initialisieren des Bildes:

%Vor%

Der Code wird ohne Probleme ausgeführt, das resultierende Bild ist jedoch nicht korrekt. Dies ist das Quellbild:

Und das ist das Ergebnis:

Ich bin mir sicher, dass das Problem in dem ersten Code liegt, den ich gepostet habe, aber falls nicht, habe ich eine kleine Adaption der Dreieck-Demo vom Vulkan SDK geschrieben, die das gleiche Ergebnis liefert . Es kann hier heruntergeladen werden. Der Source-Code ist enthalten, alles, was ich von der Dreieck-Demo geändert habe, sind die "demo_prepare_texture_image" -Funktion in tri.c (Zeilen 803 bis 903) und die "dds.cpp" und "dds" .h "Dateien. "dds.cpp" enthält den Code zum Laden der dds und zum Mapping des Bildspeichers.

Ich verwende gli , um die dds-Daten zu laden (was " funktionieren perfekt mit Vulkan "), das auch im Download enthalten ist. Um das Projekt zu erstellen, muss dem "Tri" -Projekt das Vulkan SDK-Include-Verzeichnis hinzugefügt werden, und der Pfad zu den dds muss geändert werden (tri.c, Zeile 809).

Das Quellbild ("x64 / Debug / test.dds" im Projekt) verwendet die DXT1-Komprimierung. Ich habe auch verschiedene Hardware getestet, mit dem gleichen Ergebnis.

Jeder Beispielcode zum Initialisieren / Zuordnen komprimierter Bilder würde ebenfalls sehr hilfreich sein.

    
Silverlan 21.03.2016, 17:48
quelle

1 Antwort

2

Ihr Problem ist eigentlich ziemlich einfach - in der Funktion demo_prepare_textures , der ersten Zeile, gibt es eine Variable tex_format , die auf VK_FORMAT_B8G8R8A8_UNORM gesetzt ist (was im ursprünglichen Beispiel der Fall ist). Dies wird schließlich verwendet, um das VkImageView zu erstellen. Wenn Sie dies nur in VK_FORMAT_BC1_RGBA_UNORM_BLOCK ändern, wird die Textur korrekt auf dem Dreieck angezeigt.

Nebenbei: Sie können überprüfen, ob Ihre Textur korrekt geladen wurde, mit RenderDoc , das mit der Installation des Virus SDK geliefert wird. Bei einer Erfassung des Tabs " TextureViewer " auf der Registerkarte Inputs zeigt die Registerkarte %code% an, dass Ihre Textur identisch mit der auf der Festplatte ist, auch wenn das Format nicht korrekt ist.

    
MuertoExcobito 25.03.2016, 11:10
quelle