ライブラリの内部構造
このトピックでは、DirectXMath ライブラリの内部設計について説明します。
- 呼び出し規約
- グラフィックス ライブラリの種類の等価性
- DirectXMath ライブラリのグローバル定数
- Windows SSE と SSE2
- ルーチンバリアント
- プラットフォームの不整合
- プラットフォーム固有の拡張機能
- 関連トピック
呼び出し規則
移植性を高め、データ レイアウトを最適化するには、DirectXMath ライブラリでサポートされているプラットフォームごとに適切な呼び出し規則を使用する必要があります。 具体的には、 XMVECTOR オブジェクトをパラメーターとして渡す場合(16 バイト境界にアラインされたものとして定義されます)、呼び出しの要件のセットは、ターゲット プラットフォームによって異なります。
32 ビット Windows の場合
32 ビット Windows の場合、 __m128 値を効率的に渡すために使用できる 2 つの呼び出し規則があります (この呼び出し規則は、そのプラットフォームに XMVECTOR を実装します)。 標準は __fastcallであり、最初の 3 つの __m128 値 (XMVECTOR インスタンス) を引数として SSE/SSE2 レジスタの関数に渡すことができます。 __fastcall は、スタックを介して残りの引数を渡します。
新しい Microsoft Visual Studio コンパイラでは、新しい呼び出し規則がサポートされています。__vectorcall、最大 6 つの __m128 値 (XMVECTOR インスタンス) を 引数として SSE/SSE2 レジスタの関数に渡すことができます。 また、十分なスペースがある場合は、SSE/SSE2 レジスタを介して異種ベクター集計 (XMMATRIX とも呼ばれます) を渡すこともできます。
64 ビット エディションの Windows の場合
64 ビット Windows の場合、 __m128 値を効率的に渡すために使用できる呼び出し規則が 2 つあります。 標準は __fastcallであり、スタック上のすべての __m128 値を渡します。
新しい Visual Studio コンパイラでは、__vectorcall呼び出し規則がサポートされています。これにより、SSE/SSE2 レジスタの関数に最大 6 つの__m128値 (XMVECTOR インスタンス) を引数として渡すことができます。 また、十分なスペースがある場合は、SSE/SSE2 レジスタを介して異種ベクター集計 (XMMATRIX とも呼ばれます) を渡すこともできます。
ARM 上の Windows の場合
ARM & ARM64 上の Windows では、最初の 4 つの__n128値 (XMVECTOR インスタンス) のインレジスタの受け渡しがサポートされています。
DirectXMath ソリューション
FXMVECTOR、GXMVECTOR、HXMVECTOR、CXMVECTOR の各エイリアスは、次の規則をサポートしています。
- FXMVECTOR エイリアスを使用して、関数の引数として使用される XMVECTOR の最初の 3 つのインスタンスに渡します。
- 引数として使用される XMVECTOR の 4 番目のインスタンスを関数に渡すには、GXMVECTOR エイリアスを使用します。
- HXMVECTOR エイリアスを使用して、引数として使用される XMVECTOR の 5 番目と 6 番目のインスタンスを関数に渡します。 その他の考慮事項については、__vectorcallドキュメントを参照してください。
- 引数として使用される XMVECTOR のそれ以上のインスタンスを渡すには 、CXMVECTOR エイリアスを使用します。
注意
出力パラメーターの場合は、必ず XMVECTOR* または XMVECTOR& を使用し、入力パラメーターに対する上記の規則に関しては無視してください。
__vectorcallに制限があるため、C++ コンストラクターには GXMVECTOR または HXMVECTOR を使用しないことをお勧めします。 最初の 3 つの XMVECTOR 値には FXMVECTOR を使用し、残りの値には CXMVECTOR を使用します。
FXMMATRIX エイリアスと CXMMATRIX エイリアスは、__vectorcallで渡す HVA 引数を利用するのに役立ちます。
- 関数に引数として最初の XMMATRIX を渡すには、FXMMATRIX エイリアスを使用します。 これは、2 つ以上の FXMVECTOR 引数、または行列の "right" に対する 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;
注意
すべての関数はインラインで宣言されており、多くの場合、コンパイラはこれらの関数に対して呼び出し規則を使用する必要はありませんが、コンパイラが関数をインライン化しない方が効率的であると判断する場合があり、このような場合は各プラットフォームで可能な限り最高の呼び出し規則が必要です。
グラフィックス ライブラリの種類の等価性
DirectXMath ライブラリの使用をサポートするために、多くの DirectXMath ライブラリの型と構造体は、 D3DDECLTYPE 型と D3DFORMAT 型の Windows 実装と、 DXGI_FORMAT 型と同等です。
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 のみ) 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、すべての AMD K8 以降のプロセッサ、およびすべての x64 対応プロセッサが導入されて以来、すべての Intel プロセッサでサポートされています。
注意
x86 以降のWindows 8には、SSE2 のサポートが必要です。 Windows x64 のすべてのバージョンでは、SSE2 のサポートが必要です。 ARM/ARM64 上の Windows にはARM_NEONが必要です。
ルーチンバリアント
DirectXMath 関数には、作業を簡単にするバリエーションがいくつかあります。
- 比較関数を使用して、ベクター比較操作の数を減らした複雑な条件付き分岐を作成します。 これらの関数の名前は、XMVector3InBoundsR などの "R" で終わる。 関数は、UINT 戻り値として、または UINT out パラメーターとして比較レコードを返します。 XMComparision* マクロを使用して値をテストできます。
- より大きなベクター配列に対してバッチ スタイルの操作を実行するためのバッチ関数。 これらの関数の名前は、 XMVector3TransformStream などの "Stream" で終わる。 関数は入力の配列に対して動作し、出力の配列を生成します。 通常、入力と出力のストライドを受け取ります。
- より遅く、より正確な結果ではなく、より高速な推定を実装する推定関数。 これらの関数の名前は、 XMVector3NormalizeEst などの "Est" で終わる。 推定を使用した場合の品質とパフォーマンスへの影響はプラットフォームによって異なりますが、パフォーマンスに依存するコードには推定バリアントを使用することをお勧めします。
プラットフォームの不整合
DirectXMath ライブラリは、パフォーマンスに依存するグラフィックス アプリケーションやゲームでの使用を目的としています。 そのため、実装は、サポートされているすべてのプラットフォームで通常の処理を実行する最適な速度を実現するように設計されています。 境界条件での結果 (特に浮動小数点スペシャルを生成する結果) は、ターゲットごとに異なる可能性があります。 この動作は、Windows 32 ビット非組み込みターゲットの x87 制御ワードや、Windows 32 ビットと 64 ビットの両方の SSE 制御ワードなど、他の実行時設定にも依存します。 さらに、さまざまな CPU ベンダー間で境界条件に違いがあります。
数値精度が最も重要な科学やその他のアプリケーションでは DirectXMath を使用しないでください。 また、この制限は、倍精度計算やその他の拡張精度計算のサポートが不足している場合にも反映されます。
注意
一般に、_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 on MSDN 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
関連トピック
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示