Freigeben über


Vergleichen der OpenGL ES 2.0-Shaderpipeline mit Direct3D

Wichtige APIs

Konzeptionell ähnelt die Direct3D 11-Shaderpipeline dem in OpenGL ES 2.0. Im Hinblick auf das API-Design sind jedoch die hauptkomponenten zum Erstellen und Verwalten der Shaderphasen Teile von zwei primären Schnittstellen, ID3D11Device1 und ID3D11DeviceContext1. In diesem Thema wird versucht, allgemeine OpenGL ES 2.0-Shaderpipeline-API-Muster den Direct3D 11-Entsprechungen in diesen Schnittstellen zuzuordnen.

Überprüfen der Direct3D 11-Shaderpipeline

Die Shaderobjekte werden mit Methoden auf der ID3D11Device1-Schnittstelle erstellt, z. B. ID3D11Device1::CreateVertexShader und ID3D11Device1::CreatePixelShader.

Die Direct3D 11-Grafikpipeline wird von Instanzen der ID3D11DeviceContext1-Schnittstelle verwaltet und weist die folgenden Phasen auf:

  • Eingabeassemblerphase. Die Eingabeassemblerphase liefert Daten (Dreiecke, Linien und Punkte) an die Pipeline. ID3D11DeviceContext1-Methoden , die diese Stufe unterstützen, haben das Präfix "IA".
  • Vertex-Shader-Stufe – Die Vertex-Shader-Stufe verarbeitet Scheitelpunkte, in der Regel Ausführen von Vorgängen wie Transformationen, Skinning und Beleuchtung. Ein Vertex-Shader verwendet immer einen einzelnen Eingabevertex und erzeugt einen einzelnen Ausgabevertex. ID3D11DeviceContext1-Methoden , die diese Stufe unterstützen, haben das Präfix "VS".
  • Streamausgabestufe – Die Streamausgabestufe streamt primitive Daten aus der Pipeline in den Arbeitsspeicher auf dem Weg zum Rasterizer. Daten können ausgestreamt und/oder an den Rasterizer übergeben werden. Daten, die aus dem Arbeitsspeicher gestreamt werden, können als Eingabedaten oder aus der CPU wieder in die Pipeline umgeleitet werden. ID3D11DeviceContext1-Methoden , die diese Stufe unterstützen, haben das Präfix "SO".
  • Rasterizerstufe – Die Rasterizer-Clips grundtypen, bereitet Grundtypen für den Pixelshader vor und bestimmt, wie Pixelshader aufgerufen werden. Sie können die Rasterung deaktivieren, indem Sie der Pipeline mitteilen, dass kein Pixelshader vorhanden ist (legen Sie die Pixelshaderstufe auf NULL mit ID3D11DeviceContext::P SSetShader) fest, und deaktivieren Sie tiefen- und Schablonentests (legen Sie DepthEnable und Schablonen auf FALSE in D3D11_DEPTH_STENCIL_DESC fest). Die Rasterungsbezogene Pipelinezähler werden zwar deaktiviert, werden jedoch nicht aktualisiert.
  • Pixel-Shader-Stufe – Die Pixel-Shader-Phase empfängt interpolierte Daten für einen Grundtyp und generiert Daten pro Pixel, z. B. Farbe. ID3D11DeviceContext1-Methoden , die diese Stufe unterstützen, haben das Präfix "PS".
  • Ausgabezusammenführungsphase – Die Ausgabezusammenführungsphase kombiniert verschiedene Arten von Ausgabedaten (Pixel-Shaderwerte, Tiefen- und Schabloneninformationen) mit dem Inhalt des Renderziels und tiefen-/Schablonenpuffern, um das endgültige Pipelineergebnis zu generieren. ID3D11DeviceContext1-Methoden , die diese Stufe unterstützen, haben das Präfix "OM".

(Es gibt auch Phasen für Geometrie-Shader, Hull-Shader, Tesselatoren und Domänen-Shader, aber da sie keine Analoga in OpenGL ES 2.0 haben, werden wir sie hier nicht besprechen.) Eine vollständige Liste der Methoden für diese Phasen finden Sie auf den Referenzseiten ID3D11DeviceContext und ID3D11DeviceContext1. ID3D11DeviceContext1 erweitert ID3D11DeviceContext für Direct3D 11.

Erstellen eines Shaders

In Direct3D werden Shaderressourcen nicht erstellt, bevor sie kompiliert und geladen werden. Stattdessen wird die Ressource beim Laden der HLSLis erstellt. Daher gibt es keine direkt analoge Funktion zu glCreateShader, die eine initialisierte Shaderressource eines bestimmten Typs erstellt (z. B. GL_VERTEX_SHADER oder GL_FRAGMENT_SHADER). Stattdessen werden Shader erstellt, nachdem die HLSL mit bestimmten Funktionen wie ID3D11Device1::CreateVertexShader und ID3D11Device1::CreatePixelShader geladen wurde und die den Typ und die kompilierte HLSL als Parameter übernehmen.

OpenGL ES 2.0 Direct3D 11
glCreateShader Call ID3D11Device1::CreateVertexShader and ID3D11Device1::CreatePixelShader after successfully loading the compiled shader object, passing them the CSO as a buffer.

 

Kompilieren eines Shaders

Direct3D-Shader müssen als kompilierte Shaderobjektdateien (.cso)-Dateien in Universelle Windows-Plattform-Apps (UWP) vorkompiliert und mithilfe einer der Windows-Runtime Datei-APIs geladen werden. (Desktop-Apps können die Shader aus Textdateien oder Zeichenfolgen zur Laufzeit kompilieren.) Die CSO-Dateien werden aus allen HLSL-Dateien erstellt, die Teil Ihres Microsoft Visual Studio-Projekts sind, und behalten dieselben Namen nur mit der Dateierweiterung CSO bei. Stellen Sie sicher, dass sie beim Versand in Ihrem Paket enthalten sind!

OpenGL ES 2.0 Direct3D 11
glCompileShader Nicht zutreffend. Kompilieren Sie die Shader in CSO-Dateien in Visual Studio, und fügen Sie sie in Ihr Paket ein.
Verwenden von glGetShaderiv für den Kompilierungsstatus Nicht zutreffend. Sehen Sie sich die Kompilierungsausgabe des FX Compilers (FXC) von Visual Studio an, wenn Fehler bei der Kompilierung auftreten. Wenn die Kompilierung erfolgreich ist, wird eine entsprechende CSO-Datei erstellt.

 

Laden eines Shaders

Wie im Abschnitt zum Erstellen eines Shaders erwähnt, erstellt Direct3D 11 den Shader, wenn die entsprechende CSO-Datei in einen Puffer geladen und an eine der Methoden in der folgenden Tabelle übergeben wird.

OpenGL ES 2.0 Direct3D 11
ShaderSource Aufrufen von ID3D11Device1::CreateVertexShader und ID3D11Device1::CreatePixelShader nach dem erfolgreichen Laden des kompilierten Shaderobjekts.

 

Einrichten der Pipeline

OpenGL ES 2.0 verfügt über das "Shaderprogramm"-Objekt, das mehrere Shader für die Ausführung enthält. Einzelne Shader werden dem Shaderprogrammobjekt angefügt. In Direct3D 11 arbeiten Sie jedoch direkt mit dem Renderingkontext (ID3D11DeviceContext1) und erstellen Shader darauf.

OpenGL ES 2.0 Direct3D 11
glCreateProgram Nicht zutreffend. Direct3D 11 verwendet nicht die Shaderprogrammobjektstraktion.
glLinkProgram Nicht zutreffend. Direct3D 11 verwendet nicht die Shaderprogrammobjektstraktion.
glUseProgram Nicht zutreffend. Direct3D 11 verwendet nicht die Shaderprogrammobjektstraktion.
glGetProgramiv Verwenden Sie den Von Ihnen erstellten Verweis auf ID3D11DeviceContext1.

 

Erstellen Sie eine Instanz von ID3D11DeviceContext1 und ID3D11Device1 mit der statischen D3D11CreateDevice-Methode.

Microsoft::WRL::ComPtr<ID3D11Device1>          m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1>  m_d3dContext;

// ...

D3D11CreateDevice(
  nullptr, // Specify nullptr to use the default adapter.
  D3D_DRIVER_TYPE_HARDWARE,
  nullptr,
  creationFlags, // Set set debug and Direct2D compatibility flags.
  featureLevels, // List of feature levels this app can support.
  ARRAYSIZE(featureLevels),
  D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for UWP apps.
  &device, // Returns the Direct3D device created.
  &m_featureLevel, // Returns feature level of device created.
  &m_d3dContext // Returns the device's immediate context.
);

Festlegen der Viewports

Das Festlegen eines Viewports in Direct3D 11 ähnelt dem Festlegen eines Viewports in OpenGL ES 2.0. Rufen Sie in Direct3D 11 ID3D11DeviceContext::RSSetViewports mit einem konfigurierten CD3D11_VIEWPORT auf.

Direct3D 11: Festlegen eines Viewports.

CD3D11_VIEWPORT viewport(
        0.0f,
        0.0f,
        m_d3dRenderTargetSize.Width,
        m_d3dRenderTargetSize.Height
        );
m_d3dContext->RSSetViewports(1, &viewport);
OpenGL ES 2.0 Direct3D 11
glViewport CD3D11_VIEWPORT, ID3D11DeviceContext::RSSetViewports

 

Konfigurieren der Vertex-Shader

Das Konfigurieren eines Vertex-Shaders in Direct3D 11 erfolgt beim Laden des Shaders. Uniforms werden als Konstantenpuffer mit ID3D11DeviceContext1::VSSetConstantBuffers1 übergeben.

OpenGL ES 2.0 Direct3D 11
glAttachShader ID3D11Device1::CreateVertexShader
glGetShaderiv, glGetShaderSource ID3D11DeviceContext1::VSGetShader
glGetUniformfv, glGetUniformiv ID3D11DeviceContext1::VSGetConstantBuffers1.

 

Konfigurieren der Pixelshader

Das Konfigurieren eines Pixelshadrs in Direct3D 11 erfolgt beim Laden des Shaders. Uniforms werden als Konstantenpuffer mit ID3D11DeviceContext1::P SSetConstantBuffers1 übergeben.

OpenGL ES 2.0 Direct3D 11
glAttachShader ID3D11Device1::CreatePixelShader
glGetShaderiv, glGetShaderSource ID3D11DeviceContext1::P SGetShader
glGetUniformfv, glGetUniformiv ID3D11DeviceContext1::P SGetConstantBuffers1.

 

Generieren der endgültigen Ergebnisse

Wenn die Pipeline abgeschlossen ist, zeichnen Sie die Ergebnisse der Shaderstufen in den Hintergrundpuffer. In Direct3D 11 wird, genau wie bei Open GL ES 2.0, ein Draw-Befehl aufgerufen, um die Ergebnisse als Farbzuordnung im Hintergrundpuffer auszugeben, und dann diesen Hintergrundpuffer an die Anzeige zu senden.

OpenGL ES 2.0 Direct3D 11
glDrawElements ID3D11DeviceContext1::D raw, ID3D11DeviceContext1::D rawIndexed (oder andere Draw*-Methoden für ID3D11DeviceContext1).
eglSwapBuffers IDXGISwapChain1::P resent1

 

Portieren von GLSL zu HLSL

GLSL und HLSL unterscheiden sich nicht sehr von komplexer Typunterstützung und Syntax einiger gesamter Syntax. Viele Entwickler finden es am einfachsten, zwischen den beiden zu portieren, indem allgemeine OpenGL ES 2.0-Anweisungen und Definitionen zu ihrer HLSL-Entsprechung aliast werden. Beachten Sie, dass Direct3D die Shadermodellversion verwendet, um den Featuresatz der hlSL auszudrücken, die von einer Grafikschnittstelle unterstützt wird; OpenGL weist eine andere Versionsspezifikation für HLSL auf. In der folgenden Tabelle wird versucht, ihnen eine ungefähre Vorstellung von den für Direct3D 11 und OpenGL ES 2.0 definierten Shader-Sprachfeatures in Bezug auf die Version der anderen zu geben.

Shadersprache GLSL-Featureversion Direct3D-Shadermodell
Direct3D 11 HLSL ~4,30. SM 5.0
GLSL ES für OpenGL ES 2.0 1.40. Ältere Implementierungen von GLSL ES für OpenGL ES 2.0 können 1.10 bis 1.30 verwenden. Überprüfen Sie ihren ursprünglichen Code mit glGetString(GL_SHADING_LANGUAGE_VERSION) oder glGetString(SHADING_LANGUAGE_VERSION), um ihn zu ermitteln. ~SM 2.0

 

Weitere Informationen zu unterschieden zwischen den beiden Shadersprachen sowie gängigen Syntaxzuordnungen finden Sie in der GLSL-zu-HLSL-Referenz.

Portieren der systeminternen OpenGL-Daten zur HLSL-Semantik

Direct3D 11 HLSL-Semantik sind Zeichenfolgen, die wie ein Uniform- oder Attributname verwendet werden, um einen wert zu identifizieren, der zwischen der App und einem Shaderprogramm übergeben wird. Obwohl es sich um eine Vielzahl möglicher Zeichenfolgen handelt, empfiehlt es sich, eine Zeichenfolge wie POSITION oder COLOR zu verwenden, die die Verwendung angibt. Sie weisen diese Semantik zu, wenn Sie einen Konstantenpuffer oder ein Puffereingabelayout erstellen. Sie können der Semantik auch eine Zahl zwischen 0 und 7 anfügen, sodass Sie für ähnliche Werte separate Register verwenden. Beispiel: COLOR0, COLOR1, COLOR2...

Semantik, die dem Präfix "SV_" vorangestellt ist, sind Systemwertsemantik, die von Ihrem Shaderprogramm geschrieben werden; Ihre App selbst (ausgeführt auf der CPU) kann sie nicht ändern. In der Regel enthalten diese Werte, die Eingaben oder Ausgaben aus einer anderen Shaderstufe in der Grafikpipeline sind oder vollständig von der GPU generiert werden.

Darüber hinaus weisen SV_ Semantik unterschiedliche Verhaltensweisen auf, wenn sie zum Angeben von Eingaben oder Ausgaben aus einer Shaderstufe verwendet werden. Beispielsweise enthält SV_POSITION (Ausgabe) die vertexdaten, die während der Vertex-Shaderphase transformiert wurden, und SV_POSITION (Eingabe) enthält die Pixelpositionswerte, die während der Rasterung interpoliert werden.

Hier sind einige Zuordnungen für allgemeine systeminterne OpenGL ES 2.0-Shader:

OpenGL-Systemwert Verwenden Sie diese HLSL-Semantik
gl_Position POSITION(n) für Vertexpufferdaten. SV_POSITION stellt eine Pixelposition für den Pixelshader bereit und kann von Ihrer App nicht geschrieben werden.
gl_Normal NORMAL(n) für normale Daten, die vom Vertexpuffer bereitgestellt werden.
gl_TexCoord[n] TEXCOORD(n) für Textur-UV-Koordinatendaten (ST in einigen OpenGL-Dokumentationen), die für einen Shader bereitgestellt werden.
gl_FragColor COLOR(n) für RGBA-Farbdaten, die für einen Shader bereitgestellt werden. Beachten Sie, dass sie identisch mit Koordinatendaten behandelt wird; Mit der Semantik können Sie einfach erkennen, dass es sich um Farbdaten handelt.
gl_FragData[n] SV_Target[n] zum Schreiben aus einem Pixelshader in eine Zieltextur oder einen anderen Pixelpuffer.

 

Die Methode, mit der Sie eine Semantik codieren, ist nicht identisch mit der Verwendung systeminterner Elemente in OpenGL ES 2.0. In OpenGL können Sie direkt ohne Konfiguration oder Deklaration auf viele systeminterne Elemente zugreifen; In Direct3D müssen Sie ein Feld in einem bestimmten Konstantenpuffer deklarieren, um eine bestimmte Semantik zu verwenden, oder Sie deklarieren es als Rückgabewert für die Main()-Methode eines Shaders.

Hier ist ein Beispiel für eine Semantik, die in einer Konstantenpufferdefinition verwendet wird:

struct VertexShaderInput
{
  float3 pos : POSITION;
  float3 color : COLOR0;
};

// The position is interpolated to the pixel value by the system. The per-vertex color data is also interpolated and passed through the pixel shader. 
struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR0;
};

Dieser Code definiert ein Paar einfacher Konstantenpuffer.

Hier ist ein Beispiel für eine Semantik, die zum Definieren des von einem Fragment-Shader zurückgegebenen Werts verwendet wird:

// A pass-through for the (interpolated) color data.
float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color,1.0f);
}

In diesem Fall ist SV_TARGET die Position des Renderziels, in das die Pixelfarbe (definiert als Vektor mit vier Float-Werten) geschrieben wird, wenn der Shader die Ausführung abgeschlossen hat.

Weitere Informationen zur Verwendung von Semantik mit Direct3D finden Sie unter HLSL-Semantik.