DirectXMath ライブラリを使用したコード最適化
このトピックでは、DirectXMath ライブラリの最適化に関する考慮事項と戦略について説明します。
- アクセサーを慎重に使用する
- 正しいコンパイル設定を使用する
- 必要に応じて Est 関数を使用する
- 配置されたデータ型と操作を使用する
- 割り当てを適切に配置する
- 可能な場合は演算子のオーバーロードを回避する
- 非正規化数
- 整数浮動小数点の二重性を活用する
- テンプレート フォームを優先する
- Direct3D での DirectXMath の使用
- 関連トピック
アクセサーを慎重に使用する
ベクター ベースの操作では SIMD 命令セットが使用され、特殊なレジスタが使用されます。 個々のコンポーネントにアクセスするには、SIMD レジスタからスカラー レジスタに移動し、もう一度戻る必要があります。
可能であれば、一連の個々のベクター アクセサーを使用するのではなく、 XMVECTOR のすべてのコンポーネントを一度に初期化する方が効率的です。
正しいコンパイル設定を使用する
Windows x86 ターゲットの場合は、/arch:SSE2 を有効にします。 すべての Windows ターゲットに対して、/fp:fast を有効にします。
既定では、Windows x86 ターゲットの DirectXMath ライブラリに対するコンパイルは、_XM_SSE_INTRINSICS_定義された状態で行われます。 つまり、すべての DirectXMath 機能で SSE2 命令が使用されます。 ただし、他のコードについても同じことは当てはまりません。
DirectXMath 以外のコードは、コンパイラの既定値を使用して処理されます。 このスイッチがないと、生成されたコードでは、効率の低い x87 コードが使用されることがよくあります。
常に最新バージョンのコンパイラを使用することを強くお勧めします。
必要に応じて Est 関数を使用する
多くの関数には、Est で終わる同等の推定関数があります。 これらの関数は、パフォーマンスを向上させるために、ある程度の精度を交換します。 Est 関数は、速度のために精度を犠牲にすることができる重要でない計算に適しています。 失われた正確さと速度の増加の正確な量は、プラットフォームによって異なります。
たとえば、 XMVector3AngleBetweenNormalsEst 関数は 、XMVector3AngleBetweenNormals 関数の代わりに使用できます。
配置されたデータ型と操作を使用する
SSE2 をサポートする Windows のバージョンに対する SIMD 命令セットは、通常、メモリ操作のアラインメントバージョンとアラインされていないバージョンを備えています。 アラインされた操作の使用は高速であり、可能な限り優先する必要があります。
DirectXMath ライブラリは、バリアント ベクター型、構造体、および関数を通じて、アラインおよびアラインされていないアクセス機能を提供します。 これらのバリアントは、名前の末尾に "A" で示されます。
たとえば、XMStoreFloat4 関数と XMStoreFloat4A 関数でそれぞれ使用される、アラインされていない XMFLOAT4X4 構造体と、アラインされた XMFLOAT4X4A 構造体があります。
割り当てを適切に配置する
DirectXMath ライブラリの基になる SSE 組み込みのアラインされたバージョンは、整列されていないバージョンよりも高速です。
このため、 XMVECTOR オブジェクトと XMMATRIX オブジェクトを使用する DirectXMath 操作では、これらのオブジェクトが 16 バイトアラインされていることを前提としています。 これは、推奨される Windows (「 正しいコンパイル設定を使用する」を参照) コンパイラ設定を使用して DirectXMath ライブラリに対してコードがコンパイルされる場合、スタック ベースの割り当てに対して自動的に行われます。 ただし、 XMVECTOR オブジェクトと XMMATRIX オブジェクトを含むヒープ割り当て、またはこれらの型へのキャストが、これらのアラインメント要件を満たしていることを確認することが重要です。
64 ビットの Windows メモリ割り当ては 16 バイトアラインメントされますが、割り当てられた 32 ビット バージョンの Windows メモリでは、既定では 8 バイトアラインメントのみが行われます。 メモリ配置の制御については、「 _aligned_malloc」を参照してください。
標準テンプレート ライブラリ (STL) で配置された DirectXMath 型を使用する場合は、16 バイトのアラインメントを保証するカスタム アロケーターを指定する必要があります。 カスタム アロケーターを記述する例については、Visual C++ チーム のブログ を参照してください (malloc/free ではなく、実装で_aligned_mallocと_aligned_freeを使用する必要があります)。
注意
一部の STL テンプレートでは、指定された型の配置が変更されます。 たとえば、 make_shared<> は、提供されたユーザーの種類のアラインメントを考慮する場合と考慮されない可能性がある内部追跡情報を追加し、結果としてデータ メンバーが整列されません。 この場合は、アラインされた型ではなく、整列されていない型を使用する必要があります。 多くのWindows ランタイム オブジェクトを含む既存のクラスから派生した場合は、クラスまたは構造体の配置を変更することもできます。
可能な場合は演算子のオーバーロードを回避する
便利な機能として、 XMVECTOR や XMMATRIX などの多くの型には、一般的な算術演算の演算子オーバーロードがあります。 このような演算子オーバーロードは、多数の一時オブジェクトを作成する傾向があります。 パフォーマンスに依存するコードでは、これらの演算子のオーバーロードを回避することをお勧めします。
非正規化数
0 に近い計算をサポートするために、IEEE 754 浮動小数点標準には段階的なアンダーフローのサポートが含まれています。 段階的なアンダーフローは非正規化値を使用して実装され、非正規化を処理する場合、多くのハードウェア実装が遅くなります。 考慮すべき最適化は、DirectXMath で使用されるベクター操作の非正規化の処理を無効にすることです。
非正規化の処理の変更は、 _controlfp_s ルーチンをスレッド前に使用することによって行われ、パフォーマンスが向上する可能性があります。 次のコードを使用して、非正規化の処理を変更します。
#include <float.h>;
unsigned int control_word;
_controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
注意
64 ビット バージョンの Windows では、ベクター操作だけでなく、すべての計算に SSE 命令が使用されます。 非正規処理を変更すると、DirectXMath で使用されるベクトル演算だけでなく、プログラム内のすべての浮動小数点計算に影響します。
整数浮動小数点の二重性を活用する
DirectXMath では、4 つの単精度浮動小数点または 4 つの 32 ビット (符号付きまたは符号なし) 値のベクトルがサポートされています。
DirectXMath ライブラリの実装に使用される命令セットには、同じデータを複数の異なる型として扱う機能があるため、同じベクターを浮動小数点データとして扱い、整数データ固有の最適化を実現できます。 これらの最適化を取得するには、整数ベクトル初期化ルーチンとビットごとの演算子を使用して浮動小数点値を操作します。
DirectXMath ライブラリで使用される単精度浮動小数点数のバイナリ形式は、IEEE 754 標準に完全に準拠しています。
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
IEEE 754 単精度浮動小数点数を使用する場合は、一部の表現が特別な意味を持つ (つまり、前の説明に準拠していない) 点に留意することが重要です。 たとえば、次のようになります。
- 正のゼロは 0 です
- 負のゼロが0x80000000
- Q_NANは 07FC0000 です
- +INF が0x7F800000
- -INF が0xFF800000
テンプレート フォームを優先する
XMVectorSwizzle、XMVectorPermute、XMVectorInsert、XMVectorShiftLeft、XMVectorRotateLeft、および XMVectorRotateRight のテンプレート フォームが存在します。 一般的な関数形式の代わりにこれらを使用すると、コンパイラはより効率的な実装を作成できます。 SSE の場合、これは多くの場合、1 つまたは 2 つの_mm_shuffle_ps値に折りたたまれます。 ARM-NEON の場合、 XMVectorSwizzle テンプレートでは、一般的な VTBL スワイズル/パーミュートではなく、いくつかの特殊なケースを利用できます。
Direct3D での DirectXMath の使用
DirectXMath の一般的な用途は、Direct3D で使用するグラフィックス計算を実行する方法です。 Direct3D 10.x および Direct3D 11.x では、DirectXMath ライブラリを次の直接の方法で使用できます。
Id3D11DeviceContext::ClearRenderTargetView メソッドまたは ID3D10Device::ClearRenderTargetView メソッドの呼び出しで、ColorRGBA パラメーターで Colors 名前空間定数を直接使用します。 Direct3D 9 の場合、IDirect3DDevice9::Clear メソッドの呼び出しで Color パラメーターとして使用するには、XMCOLOR 型に変換する必要があります。
XMFLOAT4/XMVECTOR 型と XMFLOAT4X4/XMMATRIX 型を使用して、HLSL float4 型または matrix/float4x4 型による参照用の定数バッファー構造を設定します。
注意
XMFLOAT4X4/XMMATRIX 型は行メジャー形式です。 したがって、/Zpr コンパイラ スイッチ (D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR コンパイル フラグ) を使用するか、HLSL でマトリックス型を宣言するときにrow_majorキーワード (keyword)を省略する場合は、定数バッファーに設定するときに行列を入れ替える必要があります。
Direct3D 10.x および Direct3D 11.x では、pData メンバー (D3D10_MAPPED_TEXTURE2D) の Map メソッド (ID3D11DeviceContext::Map など) によって返されるポインターを想定できます。pData、D3D10_MAPPED_TEXTURE3D。pData、またはD3D11_MAPPED_SUBRESOURCE。pData)は、機能レベル 10_0 以上を使用する場合、またはリソースを使用するたびに 16 バイトアラインD3D11_USAGE_STAGING。