ライブラリの内部構造
DirectXMath ライブラリのグローバル定数
- 呼び出し規約
- グラフィックスライブラリのタイプの等価性
- DirectXMath ライブラリのグローバル定数
- Windows SSE と SSE2
- ルーチンバリアント
- プラットフォームの不一致
- プラットフォーム固有の拡張機能
- 関連トピック
呼び出し規約
移植性を高め、データ レイアウトを最適化するには、DirectXMath ライブラリでサポートされている各プラットフォームに適切な呼び出し規則を使用する必要があります。 具体的には、16 バイト境界に揃えて定義されている XMVECTOR オブジェクトをパラメーターとして渡す場合、ターゲット プラットフォームに応じて呼び出し要件のセットが異なります。
For 32 ビット Windows
32 ビット Windows の場合、 __m128 値 (そのプラットフォームで XMVECTOR を実装) を効率的に渡すために使用できる呼び出し規約が 2 つあります。 標準は __fastcall であり、最初の 3 つの __m128 値 (XMVECTOR インスタンス) を SSE/SSE2 レジスタ内の関数への引数として渡すことができます。 __fastcall は残りの引数をスタック経由で渡します。
新しい Microsoft Visual Studio コンパイラは、新しい呼び出し規約 __vectorcall をサポートしています。これにより、最大 6 つの __m128 値 (XMVECTOR インスタンス) を SSE/SSE2 レジスタ内の関数への引数として渡すことができます。 十分なスペースがある場合は、異種ベクトル集合体(XMMATRIX とも呼ばれる)を SSE/SSE2 レジスタ経由で渡すこともできます。
64ビット版Windowsの場合
64 ビット Windows では、 __m128 値を効率的に渡すために 2 つの呼び出し規約が利用できます。 標準は __fastcallであり、これはすべての __m128 値をスタックに渡します。
新しい Visual Studio コンパイラは、最大 6 つの __m128 値 (XMVECTOR インスタンス) を SSE/SSE2 レジスタ内の関数への引数として渡すことができる __vectorcall 呼び出し規約をサポートしています。 十分なスペースがある場合は、異種ベクトル集合体(XMMATRIX とも呼ばれる)を SSE/SSE2 レジスタ経由で渡すこともできます。
ARM版Windowsの場合
ARM & ARM64 上の Windows は、最初の 4 つの __n128 値 (XMVECTOR インスタンス) をレジスタに渡すことをサポートしています。
DirectXMath ソリューション
FXMVECTOR、 GXMVECTOR、 HXMVECTOR、および CXMVECTOR エイリアスは、次の規則をサポートしています。
- FXMVECTOR エイリアスを使用して、関数の引数として使用される XMVECTOR の最初の 3 つのインスタンスを渡します。
- GXMVECTOR エイリアスを使用して、関数の引数として使用される XMVECTOR の 4 番目のインスタンスを渡します。
- HXMVECTOR エイリアスを使用して、関数の引数として使用される XMVECTOR の 5 番目と 6 番目のインスタンスを渡します。 追加の考慮事項については、__vectorcall のドキュメントを参照してください。
- 引数として使用される XMVECTOR の追加のインスタンスを渡すには、 CXMVECTOR エイリアスを使用します。
Note
出力パラメータの場合は、常に XMVECTOR* または XMVECTOR& を使用し、入力パラメータの前述のルールについては無視します。
__vectorcall の制限のため、C++ コンストラクターには GXMVECTOR または HXMVECTOR を使用しないことをお勧めします。 最初の 3 つの XMVECTOR 値には FXMVECTOR を使用し、残りには CXMVECTOR を使用します。
FXMMATRIX および CXMMATRIX エイリアスは、__vectorcall による HVA 引数の受け渡しを活用することをサポートします。
- FXMMATRIX エイリアスを使用して、最初の XMMATRIX を関数の引数として渡します。 これは、行列の「右側」に 2 つ以上の FXMVECTOR 引数、または 2 つ以上の float、double、または FXMVECTOR 引数がないことを前提としています。 追加の考慮事項については、__vectorcall のドキュメントを参照してください。
- それ以外の場合は、 CXMMATRIX エイリアスを使用します。
__vectorcall の制限のため、C++ コンストラクターには FXMMATRIX を使用しないことをお勧めします。 CXMMATRIXを使用するだけです。
型エイリアスに加えて、XM_CALLCONV アノテーションを使用して、関数がコンパイラとアーキテクチャに基づいて適切な呼び出し規約 (__fastcall と __vectorcall) を使用するようにする必要があります。 __vectorcall の制限のため、C++ コンストラクターには XM_CALLCONV を使用しないことをお勧めします。
以下は、この規則を説明する宣言例です。
XMMATRIX XM_CALLCONV XMMatrixLookAtLH(FXMVECTOR EyePosition, FXMVECTOR FocusPosition, FXMVECTOR UpDirection);
XMMATRIX XM_CALLCONV XMMatrixTransformation2D(FXMVECTOR ScalingOrigin, float ScalingOrientation, FXMVECTOR Scaling, FXMVECTOR RotationOrigin, float Rotation, GXMVECTOR Translation);
void XM_CALLCONV XMVectorSinCos(XMVECTOR* pSin, XMVECTOR* pCos, FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorHermiteV(FXMVECTOR Position0, FXMVECTOR Tangent0, FXMVECTOR Position1, GXMVECTOR Tangent1, HXMVECTOR T);
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3)
XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M);
XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose(FXMMATRIX M1, CXMMATRIX M2);
これらの呼び出し規則をサポートするために、これらの型エイリアスは次のように定義されます (コンパイラがレジスタ内渡しを考慮するには、パラメータを値で渡す必要があります)。
32ビットWindowsアプリの場合
__fastcall を使用する場合:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
__vectorcall を使用する場合。
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
64ビットネイティブWindowsアプリの場合
__fastcall を使用する場合:
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
__vectorcall を使用する場合。
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
ARM 版 Windows
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Note
すべての関数はインラインで宣言されており、多くの場合、コンパイラはこれらの関数に対して呼び出し規約を使用する必要はありませんが、関数をインライン化しない方が効率的であるとコンパイラが判断するケースもあり、このような場合には、各プラットフォームで可能な限り最適な呼び出し規約が必要になります。
グラフィックスライブラリのタイプの等価性
DirectXMath ライブラリの使用をサポートするために、多くの DirectXMath ライブラリの型と構造体は、 D3DDECLTYPE 型と D3DFORMAT 型、および DXGI_FORMAT 型の Windows 実装と同等です。
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (Xbox のみ) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (Xbox のみ) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4 | D3DDECLTYPE_DEC4 (Xbox のみ) | D3DDECLTYPE_DEC3 (Xbox のみ) | |
XMDECN4 | D3DDECLTYPE_DEC4N (Xbox のみ) | D3DDECLTYPE_DEC3N (Xbox のみ) | |
XMFLOAT2 | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT2A | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT3 | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3A | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3PK | DXGI_FORMAT_R11G11B10_FLOAT | ||
XMFLOAT3SE | DXGI_FORMAT_R9G9B9E5_SHAREDEXP | ||
XMFLOAT4 | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMFLOAT4A | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMHALF2 | D3DDECLTYPE_FLOAT16_2 | D3DFMT_G16R16F | DXGI_FORMAT_R16G16_FLOAT |
XMHALF4 | D3DDECLTYPE_FLOAT16_4 | D3DFMT_A16B16G16R16F | DXGI_FORMAT_R16G16B16A16_FLOAT |
XMINT2 | DXGI_FORMAT_R32G32_SINT | ||
XMINT3 | DXGI_FORMAT_R32G32B32_SINT | ||
XMINT4 | DXGI_FORMAT_R32G32B32A32_SINT | ||
XMSHORT2 | D3DDECLTYPE_SHORT2 | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SINT |
XMSHORTN2 | D3DDECLTYPE_SHORT2N | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SNORM |
XMSHORT4 | D3DDECLTYPE_SHORT4 | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SINT |
XMSHORTN4 | D3DDECLTYPE_SHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SNORM |
XMUBYTE2 | DXGI_FORMAT_R8G8_UINT | ||
XMUBYTEN2 | D3DFMT_A8P8, D3DFMT_A8L8 | DXGI_FORMAT_R8G8_UNORM | |
XMUINT2 | DXGI_FORMAT_R32G32_UINT | ||
XMUINT3 | DXGI_FORMAT_R32G32B32_UINT | ||
XMUINT4 | DXGI_FORMAT_R32G32B32A32_UINT | ||
XMU555 | D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM | |
XMU565 | D3DFMT_R5G6B5 | DXGI_FORMAT_B5G6R5_UNORM | |
XMUBYTE4 | D3DDECLTYPE_UBYTE4 | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UINT |
XMUBYTEN4 | D3DDECLTYPE_UBYTE4N | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UNORM DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM (XMLoadUDecN4_XR と XMStoreUDecN4_XRを使用します) |
XMUDEC4 | D3DDECLTYPE_UDEC4 (Xbox Only) D3DDECLTYPE_UDEC3 (Xbox のみ) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (Xbox のみ) D3DDECLTYPE_UDEC3N (Xbox のみ) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UNORM |
XMUNIBBLE4 | D3DFMT_A4R4G4B4, D3DFMT_X4R4G4B4 | DXGI_FORMAT_B4G4R4A4_UNORM (DXGI 1.2+) | |
XMUSHORT2 | D3DDECLTYPE_USHORT2 | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UINT |
XMUSHORTN2 | D3DDECLTYPE_USHORT2N | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UNORM |
XMUSHORT4 | D3DDECLTYPE_USHORT4 (Xbox のみ) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
DirectXMath ライブラリのグローバル定数
データ セグメントのサイズを縮小するために、DirectXMath ライブラリは XMGLOBALCONST マクロを使用して、実装でいくつかのグローバル内部定数を活用します。 慣例により、このような内部グローバル定数には g_XMという接頭辞が付けられます。 通常、これらは次のいずれかのタイプです: XMVECTORU32、XMVECTORF32、または XMVECTORI32。
これらの内部グローバル定数は、DirectXMath ライブラリの将来のリビジョンで変更される可能性があります。 可能な場合は、 g_XM グローバル値を直接使用するのではなく、定数をカプセル化するパブリック関数を使用します。 XMGLOBALCONST を使用して独自のグローバル定数を宣言することもできます。
Windows SSE と SSE2
SSE 命令セットは、単精度浮動小数点ベクトルのみをサポートします。 DirectXMath は、整数ベクトルのサポートを提供するために SSE2 命令セットを使用する必要があります。 SSE2 は、Pentium 4 の導入以降のすべての Intel プロセッサ、すべての AMD K8 以降のプロセッサ、およびすべての x64 対応プロセッサでサポートされています。
Note
Windows 8 for x86 以降では SSE2 のサポートが必要です。 Windows x64 のすべてのバージョンでは SSE2 のサポートが必要です。 ARM / ARM64 上の Windows には ARM_NEON が必要です。
ルーチンバリアント
DirectXMath 関数には、作業を容易にするいくつかのバリエーションがあります。
- より少数のベクトル比較演算に基づいて複雑な条件分岐を作成する比較関数。 これらの関数の名前は、XMVector3InBoundsR のように「R」で終わります。 関数は、比較レコードを UINT 戻り値として、または UINT 出力パラメータとして返します。 値をテストするには、 XMComparision* マクロを使用できます。
- より大きなベクトル配列に対してバッチ形式の操作を実行するためのバッチ関数。 これらの関数の名前は、 XMVector3TransformStreamのように「Stream」で終わります。 関数は入力の配列に対して動作し、出力の配列を生成します。 通常、入力と出力のストライドを実行します。
- より遅く、より正確な結果ではなく、より高速な推定を実装する推定関数。 これらの関数の名前は、 XMVector3NormalizeEstのように「Est」で終わります。 推定を使用した場合の品質とパフォーマンスへの影響はプラットフォームによって異なりますが、パフォーマンスが重要なコードには推定バリアントを使用することをお勧めします。
プラットフォームの不一致
DirectXMath ライブラリは、パフォーマンスが重視されるグラフィック アプリケーションやゲームで使用することを目的としています。 したがって、実装は、サポートされているすべてのプラットフォームで通常の処理を実行する際の最適な速度を実現するように設計されています。 境界条件での結果、特に浮動小数点特殊値を生成する結果は、ターゲットごとに異なる可能性があります。 この動作は、Windows 32 ビットの非組み込みターゲットの x87 制御ワードや、Windows 32 ビットと 64 ビットの両方の SSE 制御ワードなど、他の実行時設定にも依存します。 さらに、さまざまな CPU ベンダー間で境界条件が異なります。
数値の正確さが最も重要となる科学アプリケーションやその他のアプリケーションでは DirectXMath を使用しないでください。 また、この制限は、倍精度やその他の拡張精度の計算がサポートされていないことにも反映されています。
Note
_XM_NO_INTRINSICS_ スカラー コード パスは、通常、パフォーマンスではなくコンプライアンスのために記述されます。 境界条件の結果も異なります。
プラットフォーム固有の拡張機能
DirectXMath ライブラリは、幅広くサポートされている組み込み命令 (SSE2 および ARM-NEON) を使用して、x86、x64、および Windows RT プラットフォームに優れたサポートを提供し、C++ SIMD プログラミングを簡素化することを目的としています。
ただし、プラットフォーム固有の指示が有益な場合もあります。 DirectXMath の実装方法により、多くの場合、標準コンパイラでサポートされている組み込みステートメントで DirectXMath 型を直接使用したり、拡張命令をサポートしていないプラットフォームのフォールバック パスとして DirectXMath を使用したりすることが簡単になります。
たとえば、SSE 4.1 のドット積命令を活用する簡略化された例を次に示します。 実行時に無効な命令例外が発生しないように、コードパスを明示的に保護する必要があることに注意してください。 コード パスが、分岐の追加コストや複数のコード パスを維持する複雑さなどを正当化するのに十分な作業を実行することを確認します。
#include <Windows.h>
#include <stdio.h>
#include <DirectXMath.h>
#include <intrin.h>
#include <smmintrin.h>
using namespace DirectX;
bool g_bSSE41 = false;
void DetectCPUFeatures()
{
#ifndef _M_ARM
// See __cpuid documentation for more information
int CPUInfo[4] = {-1};
#if defined(__clang__) || defined(__GNUC__)
__cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 0);
#endif
if ( CPUInfo[0] >= 1 )
{
#if defined(__clang__) || defined(__GNUC__)
__cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 1);
#endif
if ( CPUInfo[2] & 0x80000 )
g_bSSE41 = true;
}
#endif
}
int main()
{
if ( !XMVerifyCPUSupport() )
return -1;
DetectCPUFeatures();
...
XMVECTORF32 v1 = { 1.f, 2.f, 3.f, 4.f };
XMVECTORF32 v2 = { 5.f, 6.f, 7.f, 8.f };
XMVECTOR r2, r3, r4;
if ( g_bSSE41 )
{
#ifndef _M_ARM
r2 = _mm_dp_ps( v1, v2, 0x3f );
r3 = _mm_dp_ps( v1, v2, 0x7f );
r4 = _mm_dp_ps( v1, v2, 0xff );
#endif
}
else
{
r2 = XMVector2Dot( v1, v2 );
r3 = XMVector3Dot( v1, v2 );
r4 = XMVector4Dot( v1, v2 );
}
...
return 0;
}
プラットフォーム固有の拡張機能の詳細については、以下を参照してください。
DirectXMath: SSE、 SSE2 および ARM-NEON
DirectXMath: SSE3 と SSSE3
DirectXMath: SSE4.1 および SSE4.2
DirectXMath: AVX
DirectXMath: F16C と FMA
DirectXMath: AVX2
DirectXMath: ARM64