Codeoptimierung mit der DirectXMath-Bibliothek
In diesem Thema werden Überlegungen und Strategien zur Optimierung mit der DirectXMath-Bibliothek beschrieben.
- Sparsame Verwendung von Accessoren
- Verwenden der richtigen Kompilierungseinstellungen
- Verwenden von Est-Funktionen bei Bedarf
- Verwenden von ausgerichteten Datentypen und Vorgängen
- Ordnungsgemäßes Ausrichten von Zuordnungen
- Vermeiden von Operatorüberladungen nach Möglichkeit
- Abbrüche
- Nutzen der Ganzzahl-Gleitkommadalität
- Vorlagenformulare bevorzugen
- Verwenden von DirectXMath mit Direct3D
- Zugehörige Themen
Sparsame Verwendung von Accessoren
Vektorbasierte Vorgänge verwenden die SIMD-Befehlssätze, die spezielle Register verwenden. Der Zugriff auf einzelne Komponenten erfordert den Wechsel von den SIMD-Registern zu den Skalarregistern und wieder zurück.
Wenn möglich, ist es effizienter, alle Komponenten eines XMVECTOR auf einmal zu initialisieren, anstatt eine Reihe einzelner Vektoraccessoren zu verwenden.
Verwenden der richtigen Kompilierungseinstellungen
Aktivieren Sie für Windows x86-Ziele /arch:SSE2. Aktivieren Sie für alle Windows-Ziele /fp:fast.
Standardmäßig erfolgt die Kompilierung für die Ziele der DirectXMath-Bibliothek für Windows x86 mit definierten _XM_SSE_INTRINSICS_. Dies bedeutet, dass alle DirectXMath-Funktionen SSE2-Anweisungen verwenden. Dasselbe gilt jedoch nicht für anderen Code.
Code außerhalb von DirectXMath wird mithilfe der Compilerstandardeinstellungen behandelt. Ohne diesen Schalter kann der generierte Code häufig den weniger effizienten x87-Code verwenden.
Es wird dringend empfohlen, immer die neueste verfügbare Version des Compilers zu verwenden.
Verwenden von Est-Funktionen bei Bedarf
Viele Funktionen verfügen über eine entsprechende Schätzfunktion, die auf Est endet. Diese Funktionen handeln einige Genauigkeiten ein, um die Leistung zu verbessern. Est-Funktionen eignen sich für nicht kritische Berechnungen, bei denen die Genauigkeit für die Geschwindigkeit geopfert werden kann. Die genaue Menge an verloren gegangener Genauigkeit und Geschwindigkeitssteigerung sind plattformabhängig.
Beispielsweise könnte die XMVector3AngleBetweenNormalsEst-Funktion anstelle der Funktion XMVector3AngleBetweenNormals verwendet werden.
Verwenden von ausgerichteten Datentypen und Vorgängen
Die SIMD-Befehlssätze für Versionen von Fenstern, die SSE2 unterstützen, verfügen in der Regel über ausgerichtete und nicht ausgerichtete Versionen von Speichervorgängen. Die Verwendung der ausgerichteten Vorgänge ist schneller und sollte nach Möglichkeit bevorzugt werden.
Die DirectXMath-Bibliothek bietet zugriffsorientierte und nicht ausgerichtete Funktionen über variantenorientierte Vektortypen, -struktur und -Funktionen. Diese Varianten werden durch ein "A" am Ende des Namens angegeben.
Beispielsweise gibt es eine nicht ausgerichtete XMFLOAT4X4-Struktur und eine ausgerichtete XMFLOAT4X4A-Struktur , die von den Funktionen XMStoreFloat4 bzw . XMStoreFloat4A verwendet werden.
Ordnungsgemäßes Ausrichten von Zuordnungen
Die aufeinander abgestimmten Versionen der systeminternen SSE,die der DirectXMath-Bibliothek zugrunde liegen, sind schneller als die nicht ausgerichteten.
Aus diesem Grund gehen DirectXMath-Vorgänge mit XMVECTOR - und XMMATRIX-Objekten davon aus, dass diese Objekte 16-Byte ausgerichtet sind. Dies ist für stapelbasierte Zuordnungen automatisch, wenn Code für die DirectXMath-Bibliothek mithilfe der empfohlenen Windows-Compilereinstellungen kompiliert wird (siehe Verwenden korrekter Kompilierungseinstellungen). Es ist jedoch wichtig sicherzustellen, dass die Heapzuordnung mit XMVECTOR - und XMMATRIX-Objekten oder Umwandlungen in diese Typen diese Ausrichtungsanforderungen erfüllt.
Während 64-Bit-Windows-Speicherbelegungen 16-Byte ausgerichtet sind, ist in 32-Bit-Versionen des zugewiesenen Windows-Arbeitsspeichers standardmäßig nur 8 Byte ausgerichtet. Informationen zum Steuern der Speicherausrichtung finden Sie unter _aligned_malloc.
Wenn Sie ausgerichtete DirectXMath-Typen mit der Standardvorlagenbibliothek (STL) verwenden, müssen Sie eine benutzerdefinierte Zuweisung bereitstellen, die die 16-Byte-Ausrichtung sicherstellt. Im Visual C++- Teamblog finden Sie ein Beispiel für das Schreiben einer benutzerdefinierten Zuweisung (anstelle von malloc/free sollten Sie _aligned_malloc und _aligned_free in Ihrer Implementierung verwenden).
Hinweis
Einige STL-Vorlagen ändern die Ausrichtung des bereitgestellten Typs. Beispielsweise fügt make_shared<> einige interne Nachverfolgungsinformationen hinzu, die die Ausrichtung des bereitgestellten Benutzertyps berücksichtigen oder nicht, was zu nicht ausgerichteten Datenmembern führt. In diesem Fall müssen Sie nicht ausgerichtete Typen anstelle von ausgerichteten Typen verwenden. Wenn Sie von vorhandenen Klassen ableiten, einschließlich vieler Windows-Runtime-Objekte, können Sie auch die Ausrichtung einer Klasse oder Struktur ändern.
Vermeiden von Operatorüberladungen nach Möglichkeit
Als Praktisches Feature verfügen eine Reihe von Typen wie XMVECTOR und XMMATRIX über Operatorüberladungen für gängige arithmetische Operationen. Solche Operatorüberladungen neigen dazu, zahlreiche temporäre Objekte zu erstellen. Es wird empfohlen, diese Operatorüberladungen in leistungsabhängigem Code zu vermeiden.
Abbrüche
Um Berechnungen nahe 0 zu unterstützen, umfasst der IEEE 754-Gleitkommastandard Unterstützung für einen allmählichen Unterlauf. Der allmähliche Unterlauf wird durch die Verwendung von denormalisierten Werten implementiert, und viele Hardwareimplementierungen sind bei der Behandlung von Denormalen langsam. Eine zu berücksichtigende Optimierung besteht darin, die Behandlung von Denormalen für die von DirectXMath verwendeten Vektorvorgänge zu deaktivieren.
Das Ändern der Behandlung von Denormalen erfolgt mithilfe der _controlfp_s-Routine auf Vorthreadbasis und kann zu Leistungsverbesserungen führen. Verwenden Sie diesen Code, um die Behandlung von Denormalen zu ändern:
#include <float.h>;
unsigned int control_word;
_controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
Hinweis
Unter 64-Bit-Versionen von Windows werden SSE-Anweisungen für alle Berechnungen verwendet, nicht nur für die Vektorvorgänge. Das Ändern der denormalen Behandlung wirkt sich auf alle Gleitkommaberechnungen in Ihrem Programm aus, nicht nur auf die Vektoroperationen, die von DirectXMath verwendet werden.
Nutzen der Ganzzahl-Gleitkommadalität
DirectXMath unterstützt Vektoren von 4 Gleitkommawerten mit einfacher Genauigkeit oder vier 32-Bit-Werten (signiert oder unsigniert).
Da die Zum Implementieren der DirectXMath-Bibliothek verwendeten Anweisungssätze die Möglichkeit haben, dieselben Daten wie mehrere verschiedene Typen zu behandeln, können sie beispielsweise denselben Vektor als Gleitkomma- und ganzzahlige Datenoptimierungen behandeln. Sie können diese Optimierungen erhalten, indem Sie die Ganzzahlvektorinitialisierungsroutinen und bitweise Operatoren verwenden, um Gleitkommawerte zu bearbeiten.
Das binäre Format von Gleitkommazahlen mit einfacher Genauigkeit, die von der DirectXMath Library verwendet werden, entspricht vollständig dem IEEE 754-Standard:
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
Bei der Arbeit mit der IEEE 754-Gleitkommazahl mit einfacher Genauigkeit ist es wichtig zu bedenken, dass einige Darstellungen eine besondere Bedeutung haben (d. h. sie entsprechen nicht der vorherigen Beschreibung). Beispiele:
- Positive Null ist 0
- Negative Null ist 0x80000000
- Q_NAN ist 07FC0000
- +INF ist 0x7F800000
- -INF ist 0xFF800000
Vorlagenformulare bevorzugen
Ein Vorlagenformular ist für XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLeft und XMVectorRotateRight vorhanden. Wenn Sie diese anstelle der allgemeinen Funktionsform verwenden, kann der Compiler wesentlich effizientere Implementierungen erstellen. Bei SSE reduziert sich dies häufig auf ein oder zwei _mm_shuffle_ps Werte. Für ARM-NEON kann die XMVectorSwizzle-Vorlage eine Reihe von Sonderfällen anstelle der allgemeineren VTBL-Swizzle/Permute verwenden.
Verwenden von DirectXMath mit Direct3D
Eine häufige Verwendung von DirectXMath besteht darin, Grafikberechnungen für die Verwendung mit Direct3D durchzuführen. Mit Direct3D 10.x und Direct3D 11.x können Sie die DirectXMath-Bibliothek auf folgende direkte Weise verwenden:
Verwenden Sie die Colors-Namespacekonstanten direkt im ColorRGBA-Parameter in einem Aufruf der ID3D11DeviceContext::ClearRenderTargetView - oder ID3D10Device::ClearRenderTargetView-Methode . Für Direct3D 9 müssen Sie in den XMCOLOR-Typ konvertieren, um ihn als Color-Parameter in einem Aufruf der IDirect3DDevice9::Clear-Methode zu verwenden.
Verwenden Sie die XMFLOAT4/XMVECTOR- und XMFLOAT4X4-XMMATRIX-Typen/, um konstante Pufferstrukturen einzurichten, die durch HLSL float4- oder matrix/float4x4-Typen referenziert werden.
Hinweis
XMFLOAT4X4/XMMATRIX-Typen befinden sich im Zeilen-Hauptformat. Wenn Sie also den Compilerschalter /Zpr (das D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR Kompilierungsflag) verwenden oder beim Deklarieren des Matrixtyps in HLSL die row_major Schlüsselwort (keyword) weglassen, müssen Sie die Matrix transponieren, wenn Sie sie in den Konstantenpuffer festlegen.
Bei Direct3D 10.x und Direct3D 11.x können Sie davon ausgehen, dass der von der Map-Methode zurückgegebene Zeiger (z. B. ID3D11DeviceContext::Map) im pData-Member (D3D10_MAPPED_TEXTURE2D.pData, D3D10_MAPPED_TEXTURE3D. pData oder D3D11_MAPPED_SUBRESOURCE. pData) ist 16 Byte ausgerichtet, wenn Sie die Featureebene 10_0 oder höher verwenden oder wenn Sie D3D11_USAGE_STAGING Ressourcen verwenden.