Effektshader-Verknüpfung
Direct2D verwendet eine Optimierung namens Effektshaderverknüpfung, die mehrere Effektgraph-Renderingdurchgänge in einen einzelnen Durchlauf kombiniert.
- Übersicht über die Verknüpfung von Effekt-Shadern
- Verwenden der Effektshaderverknüpfung
- Erstellen eines benutzerdefinierten Effekts mit Shaderverknüpfung
- Beispiel für einen verknüpfungskompatiblen Effektshader
- Kompilieren eines verknüpfungskompatiblen Shaders
- Exportieren von Funktionsspezifikationen
- Zugehörige Themen
Übersicht über die Verknüpfung von Effekt-Shadern
Die Optimierungen zum Verknüpfen von Effekt-Shadern bauen auf der HLSL-Shaderverknüpfung auf, einem Direct3D 11.2-Feature, mit dem Pixel- und Vertex-Shader zur Laufzeit generiert werden können, indem vorkompilierte Shaderfunktionen verknüpft werden. Die folgenden Abbildungen veranschaulichen das Konzept der Effektshaderverknüpfung in einem Effektdiagramm. Die erste Abbildung zeigt ein typisches Direct2D-Effektdiagramm mit vier Renderingtransformationen. Ohne Shaderverknüpfung benötigt jede Transformation einen Renderingdurchlauf und erfordert eine Zwischenoberfläche. Insgesamt erfordert dieses Diagramm 4 Durchläufe und 3 Zwischenläufe.
Die zweite Abbildung zeigt das gleiche Effektdiagramm, bei dem jede Renderingtransformation durch eine verlinkbare Funktionsversion ersetzt wurde. Direct2D kann das gesamte Diagramm verknüpfen und in einem Durchgang ausführen, ohne Zwischenschritte zu benötigen. Dies kann zu einer erheblichen Verringerung der GPU-Ausführungszeit und einer Verringerung der Spitzenauslastung des GPU-Arbeitsspeichers führen.
Effektshaderverknüpfung funktioniert auf einzelnen Transformationen innerhalb eines Effekts. Dies bedeutet, dass auch ein Graph mit einem einzelnen Effekt von der Shaderverknüpfung profitieren kann, wenn dieser Effekt mehrere gültige Transformationen aufweist.
Verwenden der Effektshaderverknüpfung
Wenn Sie eine Direct2D-Anwendung erstellen, die Effekte verwendet, müssen Sie nichts tun, um die Wirkungsshaderverknüpfung zu nutzen. Direct2D analysiert automatisch das Effektdiagramm, um die optimale Methode zum Verknüpfen der einzelnen Transformationen zu ermitteln.
Effektautoren sind dafür verantwortlich, ihre Wirkung so zu implementieren, dass die Verknüpfung von Effekt-Shadern unterstützt wird. Weitere Informationen finden Sie weiter unten im Abschnitt Erstellen eines shaderkompatiblen benutzerdefinierten Effekts . Alle integrierten Effekte unterstützen die Shaderverknüpfung.
Direct2D verknüpft benachbarte Renderingtransformationen nur in Situationen, in denen dies vorteilhaft ist. Bei der Entscheidung, ob zwei Transformationen verknüpft werden sollen, werden mehrere Faktoren berücksichtigt. Beispielsweise wird die Shaderverknüpfung nicht ausgeführt, wenn eine der Transformationen Vertex- oder Compute-Shader verwendet, da nur Pixel-Shader verknüpft werden können. Wenn ein Effekt nicht so erstellt wurde, dass er mit Shaderverknüpfungen kompatibel ist, werden umgebende Transformationen nicht damit verknüpft.
Für den Fall, dass eine solche Verknüpfungsgefahr besteht, verknüpft Direct2D keine Transformationen neben der Gefahr, sondern versucht trotzdem, den Rest des Diagramms zu verknüpfen.
Erstellen eines benutzerdefinierten Effekts mit Shaderverknüpfung
Wenn Sie einen eigenen benutzerdefinierten Direct2D-Effekt erstellen, müssen Sie sicherstellen, dass seine Transformationen die Verknüpfung von Effektshader unterstützen. Dies erfordert einige geringfügige Änderungen an der Implementierung früherer benutzerdefinierter Effekte. Wenn eine Transformation innerhalb Ihres benutzerdefinierten Effekts keine Shaderverknüpfung unterstützt, verknüpft Direct2D sie nicht mit Transformationen, die im Effektdiagramm an ihn angrenzen.
Als benutzerdefinierter Effektautor sollten Sie sich über mehrere wichtige Konzepte und Anforderungen bewusst sein:
Keine Änderungen an Schnittstellenimplementierungen
Sie müssen keinen Code ändern, der die verschiedenen Effektschnittstellen wie ID2D1DrawTransform implementiert.
Bereitstellen einer vollständigen und einer Exportfunktionsversion von Shadern
Sie müssen eine Exportfunktionsversion der Shader Ihres Effekts bereitstellen, die mit Direct2D verknüpft werden können. Darüber hinaus müssen Sie weiterhin den ursprünglichen vollständigen Shader bereitstellen. Dies liegt daran, dass Direct2D zur Laufzeit die richtige Shaderversion auswählt, je nachdem, ob die Shaderverknüpfung auf einen bestimmten Link im Diagramm angewendet werden soll.
Wenn eine Transformation nur das vollständige Pixel-Shaderblob bereitstellt (über ID2D1EffectContext::LoadPixelShader), wird sie nicht mit benachbarten Transformationen verknüpft.
Hilfsfunktionen
Direct2D bietet HLSL-Hilfsfunktionen und -makros, die automatisch sowohl die vollständige als auch die Exportfunktionsversion eines Shaders generieren. Diese Helfer finden Sie unter d2d1effecthelpers.hlsli. Darüber hinaus können Sie mit dem HLSL-Compiler (FXC) den Exportfunktions-Shader in ein privates Feld im vollständigen Shader einfügen. Auf diese Weise müssen Sie nur einmal einen Shader erstellen und beide Versionen gleichzeitig an Direct2D übergeben. Sowohl d2d1effecthelpers.hlsli als auch der FXC-Compiler sind als Teil des Windows SDK enthalten.
Die Hilfsfunktionen:
- D2DGetInput
- D2DSampleInput
- D2DSampleInputAtOffset
- D2DSampleInputAtPosition
- D2DGetInputCoordinate
- D2DGetScenePosition
- D2D_PS_ENTRY
Sie können auch zwei Versionen jedes Shaders manuell erstellen und zweimal kompilieren, solange die unten unter Exportfunktionsspezifikationen beschriebenen Spezifikationen erfüllt sind.
Nur Pixel-Shader
Direct2D unterstützt keine Verknüpfung von Compute- oder Vertex-Shadern. Wenn Ihr Effekt jedoch sowohl einen Vertex- als auch einen Pixel-Shader verwendet, kann die Ausgabe des Pixel-Shaders weiterhin verknüpft werden.
Einfache und komplexe Stichprobenentnahme
Das Verknüpfen der Shaderfunktion funktioniert, indem die Ausgabe eines Pixel-Shaderdurchlaufs mit der Eingabe eines nachfolgenden Pixel-Shaderdurchlaufs verbunden wird. Dies ist nur möglich, wenn der nutzende Pixel-Shader nur einen einzelnen Eingabewert benötigt, um seine Berechnung durchzuführen. Dieser Wert stammt normalerweise aus dem Sampling einer Eingabetextur an der Texturkoordinate, die vom Vertex-Shader ausgegeben wird. Ein solcher Pixel-Shader soll eine einfache Stichprobenentnahme durchführen.
Einige Pixel-Shader, z. B. eine gaußsche Unschärfe, berechnen ihre Ausgabe aus mehreren Eingabebeispielen und nicht nur aus einem einzelnen Beispiel. Ein solcher Pixel-Shader soll eine komplexe Stichprobenentnahme durchführen.
Nur Shaderfunktionen mit einfachen Eingaben können ihre Eingaben von einer anderen Shaderfunktion bereitstellen. Shaderfunktionen mit komplexen Eingaben müssen zum Beispiel mit einer Eingabetextur versehen werden. Dies bedeutet, dass Direct2D einen Shader nicht mit komplexen Eingaben mit seinem Vorgänger verknüpft.
Wenn Sie die Direct2D HLSL-Hilfsprogramme verwenden, müssen Sie in der HLSL angeben, ob ein Shader komplexe oder einfache Eingaben verwendet.
Beispiel für einen verknüpfungskompatiblen Effektshader
Mithilfe der D2D-Hilfsprogramme stellt der folgende Codeausschnitt einen einfachen verknüpfungskompatiblen Effektshader dar:
#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE
#include “d2d1effecthelpers.hlsli”
D2D_PS_ENTRY(LinkingCompatiblePixelShader)
{
float4 input = D2DGetInput(0);
input.rgb *= input.a;
return input;
}
Beachten Sie in diesem kurzen Beispiel, dass keine Funktionsparameter deklariert werden, dass die Anzahl der Eingaben und der Typ jeder Eingabe vor der Eingabefunktion deklariert werden, dass die Eingabe durch Aufrufen von D2DGetInput abgerufen wird und dass Präprozessordirektiven definiert werden müssen, bevor die Hilfsdatei enthalten ist.
Ein verknüpfungskompatibler Shader muss sowohl einen regulären Single-Pass-Pixel-Shader als auch eine Export-Shaderfunktion bereitstellen. Das D2D_PS_ENTRY Makro ermöglicht es, dass jede dieser Elemente aus demselben Code generiert wird, wenn es in Verbindung mit dem Kompilierungsskript für Shader verwendet wird.
Beim Kompilieren eines vollständigen Shaders werden die Makros in den folgenden Code erweitert, der über eine D2D-Effekte-kompatible Eingabesignatur verfügt.
Texture2D<float4> InputTexture0;
SamplerState InputSampler0;
float4 LinkingCompatiblePixelShader(
float4 pos : SV_POSITION,
float4 posScene : SCENE_POSITION,
float4 uv0 : TEXCOORD0
) : SV_Target
{
float4 input = InputTexture0.Sample(InputSampler0, uv0.xy);
input.rgb *= input.a;
return input;
}
Beim Kompilieren einer Exportfunktionsversion desselben Codes wird der folgende Code generiert:
// Shader function version
export float4 LinkingCompatiblePixelShader_Function(
float4 input0 : INPUT0)
{
input.rgb *= input.a;
return input;
}
Beachten Sie, dass die Textureingabe, die normalerweise durch Sampling einer Textur2D abgerufen wird, durch eine Funktionseingabe (input0) ersetzt wurde.
Eine vollständige, schrittweise Beschreibung der Schritte, die Sie zum Schreiben eines verknüpfungskompatiblen Effekts ausführen müssen, finden Sie im Tutorial Benutzerdefinierte Effekte und im Beispiel für benutzerdefinierte Direct2D-Bildeffekte.
Kompilieren eines verknüpfungskompatiblen Shaders
Um verlinkbar zu sein, muss das an D2D übergebene Pixel-Shaderblob sowohl die vollständige als auch die Exportfunktionsversion des Shaders enthalten. Dies wird erreicht, indem die kompilierte Exportfunktion in den D3D_BLOB_PRIVATE_DATA Bereich eingebettet wird.
Wenn die Shader mit den D2D-Hilfsfunktionen erstellt werden, muss zur Kompilierungszeit ein D2D-Kompilierungsziel definiert werden. Die Kompilierungszieltypen sind D2D_FULL_SHADER und D2D_FUNCTION.
Das Kompilieren eines verknüpfungskompatiblen Effektshaders ist ein zweistufiger Prozess:
- Kompilieren der Exportfunktion
- Kompilieren des vollständigen Shaders und Einbetten der Exportfunktion
Hinweis
Wenn Sie einen Effekt mithilfe von Visual Studio kompilieren, sollten Sie eine Batchdatei erstellen, die beide FXC-Befehle ausführt, und diese Batchdatei als benutzerdefinierten Buildschritt ausführen, der vor dem Kompilierungsschritt ausgeführt wird.
Schritt 1: Kompilieren der Exportfunktion
fxc /T <shadermodel> <MyShaderFile>.hlsl /D D2D_FUNCTION /D D2D_ENTRY=<entry> /Fl <MyShaderFile>.fxlib
Um die Exportfunktionsversion Ihres Shaders zu kompilieren, müssen Sie die folgenden Flags an FXC übergeben.
Flag | Beschreibung |
---|---|
/T <ShaderModel> | Legen Sie <ShaderModel> auf das entsprechende Pixel-Shaderprofil fest, wie in FXC Syntax definiert. Dies muss eines der Profile sein, die unter "HLSL-Shaderverknüpfung" aufgeführt sind. |
<MyShaderFile.hlsl> | Legen Sie MyShaderFile> auf den Namen der HLSL-Datei fest<. |
/D D2D_FUNCTION | Diese Definition weist FXC an, die Exportfunktionsversion des Shaders zu kompilieren. |
/D D2D_ENTRY=<entry> | Legen Sie <den Eintrag> auf den Namen des HLSL-Einstiegspunkts fest, den Sie innerhalb des D2D_PS_ENTRY Makros definiert haben. |
/Fl <MyShaderFile.fxlib> | Legen Sie <MyShaderfile> auf den Speicherort fest, an dem Sie die Exportfunktionsversion des Shaders speichern möchten. Beachten Sie, dass die Erweiterung .fxlib nur zur einfacheren Identifizierung dient. |
Schritt 2: Kompilieren des vollständigen Shaders und Einbetten der Exportfunktion
fxc /T ps_<shadermodel> <MyShaderFile>.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=<entry> /E <entry> /setprivate <MyShaderFile>.fxlib /Fo <MyShader>.cso /Fh <MyShader>.h
Um die Vollversion Ihres Shaders mit eingebetteter Exportversion zu kompilieren, müssen Sie die folgenden Flags an FXC übergeben.
Flag | Beschreibung |
---|---|
/T <ShaderModel> | Legen Sie <ShaderModel> auf das entsprechende Pixel-Shaderprofil fest, wie in FXC Syntax definiert. Dies muss das Pixel-Shaderprofil sein, das dem in Schritt 1 angegebenen Verknüpfungsprofil entspricht. |
<MyShaderFile.hlsl> | Legen Sie MyShaderFile> auf den Namen der HLSL-Datei fest<. |
/D D2D_FULL_SHADER | Diese Definition weist FXC an, die Vollversion des Shaders zu kompilieren. |
/D D2D_ENTRY=<entry> | Legen Sie den Eintrag> auf den Namen des HLSL-Einstiegspunkts fest<, den Sie im Makro D2D_PS_ENTRY() definiert haben. |
Eintrag "/E <"> | Legen Sie den Eintrag> auf den Namen des HLSL-Einstiegspunkts fest<, den Sie im Makro D2D_PS_ENTRY() definiert haben. |
/setprivate <MyShaderFile.fxlib> | Dieses Argument weist FXC an, den in Schritt 1 generierten Exportfunktionsshader in den D3D_BLOB_PRIVATE_DATA Bereich einzubetten. |
/Fo <MyShader.cso> | Legen Sie <MyShader> auf den Speicherort für den endgültigen, kombinierten kompilierten Shader fest. |
/Fh <MyShader.h> | Legen Sie <MyShader> auf fest, wo Sie den endgültigen kombinierten Header speichern möchten. |
Exportieren von Funktionsspezifikationen
Es ist möglich – aber nicht empfohlen –, einen kompatiblen Effekt-Shader zu erstellen, ohne die von D2D bereitgestellten Hilfsprogramme zu verwenden. Es muss darauf geachtet werden, dass sowohl die vollständigen Shader- als auch die Exportfunktionseingabesignaturen den D2D-Spezifikationen entsprechen.
Die Spezifikationen für vollständige Shader sind identisch mit früheren Windows-Versionen. Kurz gesagt, die Pixel-Shader-Eingabeparameter müssen SV_POSITION, SCENE_POSITION und ein TEXCOORD pro Effekteingabe sein.
Für die Exportfunktion muss die Funktion einen float4 zurückgeben, und ihre Eingaben müssen einer der folgenden Typen sein:
Einfache Eingabe
float4 d2d_inputN : INPUTN
Bei einfachen Eingaben fügt D2D entweder eine Sample-Funktion zwischen der Eingabetextur und der Shaderfunktion ein, oder die Eingabe wird von der Ausgabe einer anderen Shaderfunktion bereitgestellt.
Komplexe Eingabe
float4 d2d_uvN : TEXCOORDN
Bei komplexen Eingaben übergibt D2D nur eine Texturkoordinate, wie in Windows 8 Dokumentation beschrieben.
Ausgabeverzeichnis
float4 d2d_posScene : SCENE_POSITION
Es kann nur eine SCENE_POSITION Eingabe definiert werden. Dieser Parameter sollte nur bei Bedarf eingeschlossen werden, da nur eine Funktion pro verknüpftem Shader diesen Parameter verwenden kann.
Die Semantik muss wie oben definiert werden, da D2D die Semantik untersucht, um zu entscheiden, wie Funktionen miteinander verknüpft werden sollen. Wenn eine Funktionseingabe nicht mit einem der oben genannten Typen übereinstimmt, wird die Funktion für die Shaderverknüpfung abgelehnt.
Zugehörige Themen