このトピックでは、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" で示されます。
たとえば、アライメントされていないXMFLOAT4X4構造体と、XMStoreFloat4 関数と XMStoreFloat4A 関数でそれぞれ使用されるアライン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 型に変換する必要があります。
HLSLfloat4 型または matrix/float4x4 型で参照する定数バッファー構造体を設定するには、XMFLOAT4/XMVECTOR 型と XMFLOAT4X4/XMMATRIX 型を使用します。
注
XMFLOAT4X4/XMMATRIX 型は行優先形式です。 したがって、/Zpr コンパイラ スイッチ ( D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR コンパイル フラグ) を使用する場合、または HLSL でマトリックス型を宣言するときに row_major キーワード を省略する場合は、定数バッファーに設定するときにマトリックスを入れ替える必要があります。
Direct3D 10.x と Direct3D 11.x では、pData メンバー (D3D10_MAPPED_TEXTURE2D) で Map メソッド (ID3D11DeviceContext::Map など) によって返されるポインターを想定できます。pData、D3D10_MAPPED_TEXTURE3D。pData、またはD3D11_MAPPED_SUBRESOURCE。pData)は、機能レベル 10_0 以上を使用する場合、または D3D11_USAGE_STAGING リソースを使用する場合は常に 16 バイトアラインされます。