26. Mai 2026

Unterstützung für Texture Views in der Low-Level-API

Mit diesem Evergine-Release haben wir Texture Views als vollwertiges Konzept in die Low-Level-Grafik-API eingeführt. Mit Texture Views können Sie Teilbereiche innerhalb einer Textur referenzieren, Pixelformate uminterpretieren und den View-Typ ändern – ohne Kopien zu erzeugen oder zusätzlichen GPU-Speicher zu belegen. Diese Funktion bringt Evergine auf eine Linie mit modernen Grafik-APIs und beseitigt unnötige Texturkopien, die bisher die Performance beeinträchtigten.

Was ist eine Texture View?

Eine Textur auf der GPU kann viele Formen annehmen: 1D, 2D, 3D, Cube Maps, Arrays und Kombinationen davon. Moderne Grafik-APIs wie DirectX 12, Vulkan, Metal und WebGPU erlauben es nicht, eine Textur direkt an die Rendering-Pipeline zu binden. Stattdessen benötigen sie eine Texture View – ein Objekt, das beschreibt, wie die GPU die Texturdaten interpretieren soll.

Eine Texture View enthält keine eigenen Daten. Sie referenziert eine vorhandene Textur und stellt eine Linse bereit, durch die die GPU diese Daten liest oder schreibt. Sie können sie sich als Fenster in eine Textur vorstellen: Es kann die gesamte Textur oder nur einen Teil davon zeigen und die Daten sogar in einem anderen Format oder einer anderen Struktur als das Original darstellen.

Wichtigste Fähigkeiten

Texture Views in Evergine bieten vier zentrale Fähigkeiten:

Auswahl von Teilbereichen

Sie können eine Teilmenge der Mip-Level und Array-Layer einer Textur auswählen. Gesteuert wird dies über vier Parameter: baseMip, mipCount, baseLayer und layerCount.

Angenommen, Sie haben ein Texture2DArray mit 18 Layern, das die Shadow Maps von 3 Punktlichtern enthält (je 6 Würfelflächen). Sie können einzelne Texture Views erstellen, die die Layer 0–5, 6–11 und 12–17 referenzieren, und so jedem Licht eine eigene Cube-Map-View geben, ohne Daten zu duplizieren.

Uminterpretation des Formats

Texture Views können dieselben Daten mit einem anderen Pixelformat darstellen, sofern die Formate kompatibel sind. So kann eine als R8G8B8A8_UNorm gespeicherte Textur als R8G8B8A8_UNorm_SRgb betrachtet werden, um eine Gammakorrektur anzuwenden. Ebenso kann ein als D32_Float gespeicherter Depth Buffer als R32_Float betrachtet werden, damit ein Compute Shader ihn als regulären Float-Wert lesen kann.

Änderung des View-Typs

Eine Texture View kann ändern, wie die GPU die Struktur der Textur interpretiert. Ein Texture2DArray mit genau 6 Layern kann als TextureCube betrachtet werden, sodass Shader es mit Cube-Map-Koordinaten abtasten können. Das ist besonders nützlich für würfelbasierte Rendering-Techniken wie Shadow Maps für Punktlichter oder Environment Probes.

Duales Binding

Mit Texture Views können Sie aus derselben Textur sowohl eine Shader Resource View (zum Lesen) als auch eine Unordered Access View (zum Schreiben) erstellen. So kann ein Compute Shader in eine Textur schreiben und ein Pixel Shader daraus lesen, ohne dass eine Zwischenkopie erstellt werden muss.

Das Problem vor Texture Views

Vor der Einführung von Texture Views erstellte Evergine jede Textur mit einem festen View-Typ. In DirectX 11 etwa wurde eine Textur bei der Erstellung entweder als Shader Resource View oder als Unordered Access View gebunden – und diese Wahl ließ sich später nicht mehr ändern.

Durch diese Einschränkung war es unmöglich, dieselbe Textur sowohl als Eingabe als auch als Ausgabe zu verwenden. Musste ein Compute Shader in eine Textur schreiben und anschließend ein Pixel Shader daraus lesen, musste die Engine zwei separate Texturen vorhalten und eine GPU-Kopie zwischen ihnen durchführen. Das verdoppelte den Speicherverbrauch und kostete bei jedem Kopiervorgang GPU-Bandbreite.

Besonders betroffen war die Post-Processing-Pipeline: Jeder Effekt in der Kette benötigte eigene Zwischentexturen und Kopiervorgänge, was sich in komplexen Szenen zu erheblichem Overhead summierte.

Wie Texture Views in Evergine eingesetzt werden

Mit diesem Release setzen wir Texture Views intern bereits in drei zentralen Bereichen der Engine ein:

Post-Processing-Pipeline

Jeder Post-Processing-Effekt erstellt jetzt eine Texture View mit dem passenden Format über seiner Eingabetextur. Durch die Uminterpretation des Formats (über ToColorFormat()) beseitigt die Pipeline die Zwischenkopien, die bisher zwischen den Verarbeitungsknoten nötig waren.

Tone Mapping

Der Tone-Mapping-Pass benötigte bisher eine vollständige Texturkopie, bevor er die HDR-Eingabe lesen konnte. Mit Texture Views wird dieselbe Textur jetzt direkt mit einem kompatiblen Format referenziert, sodass die Kopie vollständig entfällt.

Compute Depth Bounds

Dieser Compute Shader berechnet die minimalen und maximalen Tiefenwerte in einem Frame, um die Near und Far Plane der Kamera dynamisch anzupassen und so die Tiefengenauigkeit zu erhalten. Er muss den Depth Buffer lesen, doch Tiefenformate können nicht direkt als Farbdaten abgetastet werden. Eine Texture View interpretiert das Format um, sodass der Compute Shader es lesen kann.

Texture Views in der Low-Level-API verwenden

Eine Texture View in Evergine zu erstellen, ist ganz einfach. Die Methode Factory.CreateTextureView nimmt die Quelltextur und optionale Parameter entgegen, mit denen sich die View anpassen lässt:

TextureView CreateTextureView(
    Texture texture,
    PixelFormat pixelFormat = PixelFormat.Unknown,
    uint baseMip = 0,
    uint mipCount = uint.MaxValue,
    uint baseLayer = 0,
    uint layerCount = uint.MaxValue,
    TextureType? viewType = null);

Hier drei praktische Beispiele:

Eine CubeMap-View aus einem 2D-Array mit 6 Layern erstellen

// facesTexture is a Texture2DArray with ArraySize = 6
var cubeView = gfxFactory.CreateTextureView(facesTexture, viewType: TextureType.TextureCube);

Eine Storage-View ohne Gamma für das Schreiben im Compute Shader erstellen

UAV unterstützt keine sRGB-Formate:

var facesTextureDesc = new TextureDescription
{
    Type = TextureType.Texture2DArray,
    Format = PixelFormat.R8G8B8A8_UNorm_SRgb,
    Width = 1024,
    Height = 1024,
    ArraySize = 6,
    Flags = TextureFlags.ShaderResource | TextureFlags.UnorderedAccess,
};
var facesTexture = graphicsContext.Factory.CreateTexture(ref facesTextureDesc, "Faces");
// Remove gamma for UAV compatibility
var storeView = graphicsContext.Factory.CreateTextureView(
    facesTexture, pixelFormat: facesTextureDesc.Format.WithoutGamma());

Einen Depth Buffer für das Lesen im Compute Shader uminterpretieren

var depthView = graphicsContext.Factory.CreateTextureView(
    depthTexture, pixelFormat: PixelFormat.R32_Float);

Texture Views sind in allen Rendering-Backends implementiert: DirectX 11, DirectX 12, Vulkan, Metal, WebGPU und OpenGL.

Wie es weitergeht

Dieses Release legt den Grundstein für Texture Views in Evergine. In kommenden Releases wollen wir ihren Einsatz auf weitere Teile der Engine ausdehnen.

Weitere Stufen der Rendering-Pipeline werden Texture Views übernehmen, um Zwischenkopien wo immer möglich zu vermeiden.

Außerdem wollen wir Texture Views in der High-Level-API breiter verfügbar machen, damit Entwickler diese Funktion in ihren eigenen Projekten einfacher nutzen können, ohne direkt mit der Low-Level-Schicht arbeiten zu müssen.

Fazit

Texture Views sind ein grundlegendes Konzept moderner Grafik-APIs, und Evergine unterstützt sie jetzt vollständig. Sie beseitigen unnötige Texturkopien, senken den GPU-Speicherverbrauch und ermöglichen eine flexible Uminterpretation von Daten, ohne zusätzliche Ressourcen zu belegen. Die Post-Processing-Pipeline, das Tone Mapping und die Berechnung der Depth Bounds profitieren bereits von dieser Funktion, und weitere Engine-Systeme werden in künftigen Releases folgen.

Daniel Cáceres Maña – Senior Researcher

Autor
Daniel Cáceres
Plain Concepts Research