Éléments internes de bibliothèque
Cette rubrique décrit la conception interne de la bibliothèque DirectXMath.
- Conventions d’appel
- Équivalence du type de bibliothèque graphique
- Constantes globales dans la bibliothèque DirectXMath
- Windows SSE et SSE2
- Variantes de routine
- Incohérences de la plateforme
- Extensions spécifiques à la plateforme
- Rubriques connexes
Conventions d’appel
Pour améliorer la portabilité et optimiser la disposition des données, vous devez utiliser les conventions d’appel appropriées pour chaque plateforme prise en charge par la bibliothèque DirectXMath. Plus précisément, lorsque vous transmettez des objets XMVECTOR en tant que paramètres, qui sont définis comme alignés sur une limite de 16 octets, il existe différents ensembles d’exigences d’appel, en fonction de la plateforme cible :
Pour Windows 32 bits
Pour Windows 32 bits, deux conventions d’appel sont disponibles pour une transmission efficace des valeurs __m128 (qui implémente XMVECTOR sur cette plateforme). La norme est __fastcall, qui peut passer les trois premières valeurs __m128 (instances XMVECTOR ) en tant qu’arguments à une fonction dans un registre SSE/SSE2 . __fastcall transmet les arguments restants via la pile.
Les compilateurs Microsoft Visual Studio plus récents prennent en charge une nouvelle convention d’appel, __vectorcall, qui peut transmettre jusqu’à six valeurs __m128 (instances XMVECTOR ) en tant qu’arguments à une fonction dans un registre SSE/SSE2 . Il peut également passer des agrégats vectoriels hétérogènes (également appelés XMMATRIX) via des registres SSE/SSE2 s’il y a suffisamment de place.
Pour les éditions 64 bits de Windows
Pour Windows 64 bits, deux conventions d’appel sont disponibles pour une transmission efficace des valeurs __m128 . La norme est __fastcall, qui transmet toutes les valeurs __m128 sur la pile.
Les compilateurs Visual Studio plus récents prennent en charge la convention d’appel __vectorcall, qui peut transmettre jusqu’à six valeurs __m128 (instances XMVECTOR ) en tant qu’arguments à une fonction dans un registre SSE/SSE2 . Il peut également passer des agrégats vectoriels hétérogènes (également appelés XMMATRIX) via des registres SSE/SSE2 s’il y a suffisamment de place.
Pour Windows sur ARM
Windows sur ARM64 & prend en charge le passage des quatre premières valeurs __n128 (instances XMVECTOR ) dans le registre.
Solution DirectXMath
Les alias FXMVECTOR, GXMVECTOR, HXMVECTOR et CXMVECTOR prennent en charge les conventions suivantes :
- Utilisez l’alias FXMVECTOR pour passer aux trois premières instances de XMVECTOR utilisées comme arguments à une fonction.
- Utilisez l’alias GXMVECTOR pour passer la 4e instance d’un XMVECTOR utilisé comme argument à une fonction.
- Utilisez l’alias HXMVECTOR pour passer les 5e et 6e instances d’un XMVECTOR utilisé comme argument à une fonction. Pour plus d’informations sur d’autres considérations, consultez la documentation __vectorcall.
- Utilisez l’alias CXMVECTOR pour passer d’autres instances de XMVECTOR utilisées comme arguments.
Notes
Pour les paramètres de sortie, utilisez toujours XMVECTOR* ou XMVECTOR& et ignorez-les par rapport aux règles précédentes pour les paramètres d’entrée.
En raison des limitations de __vectorcall, nous vous recommandons de ne pas utiliser GXMVECTOR ou HXMVECTOR pour les constructeurs C++. Utilisez simplement FXMVECTOR pour les trois premières valeurs XMVECTOR , puis utilisez CXMVECTOR pour le reste.
Les alias FXMMATRIX et CXMMATRIX permettent de prendre en charge la prise en charge de la transmission de l’argument HVA avec __vectorcall.
- Utilisez l’alias FXMMATRIX pour passer le premier XMMATRIX en tant qu’argument à la fonction. Cela suppose que vous n’avez pas plus de deux arguments FXMVECTOR ou plus de deux arguments float, double ou FXMVECTOR à droite de la matrice. Pour plus d’informations sur d’autres considérations, consultez la documentation __vectorcall.
- Sinon, utilisez l’alias CXMMATRIX .
En raison des limitations de __vectorcall, nous vous recommandons de ne jamais utiliser FXMMATRIX pour les constructeurs C++. Utilisez simplement CXMMATRIX.
En plus des alias de type, vous devez également utiliser l’annotation XM_CALLCONV pour vous assurer que la fonction utilise la convention d’appel appropriée (__fastcall et __vectorcall) en fonction de votre compilateur et de votre architecture. En raison des limitations de __vectorcall, nous vous recommandons de ne pas utiliser XM_CALLCONV pour les constructeurs C++.
Voici des exemples de déclarations qui illustrent cette convention :
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);
Pour prendre en charge ces conventions d’appel, ces alias de type sont définis comme suit (les paramètres doivent être passés par valeur pour que le compilateur les considère comme étant passés dans le registre) :
Pour les applications Windows 32 bits
Lorsque vous utilisez __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;
Lorsque vous utilisez __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;
Pour les applications Windows natives 64 bits
Lorsque vous utilisez __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;
Lorsque vous utilisez __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;
Windows sur ARM
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Notes
Bien que toutes les fonctions soient déclarées inline et que, dans de nombreux cas, le compilateur n’ait pas besoin d’utiliser des conventions d’appel pour ces fonctions, le compilateur peut décider qu’il est plus efficace de ne pas inliner la fonction et, dans ces cas, nous voulons la meilleure convention d’appel possible pour chaque plateforme.
Équivalence du type de bibliothèque graphique
Pour prendre en charge l’utilisation de la bibliothèque DirectXMath, de nombreux types et structures de bibliothèque DirectXMath sont équivalents aux implémentations Windows des types D3DDECLTYPE et D3DFORMAT , ainsi qu’aux types DXGI_FORMAT .
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (Xbox uniquement) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (Xbox uniquement) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4 | D3DDECLTYPE_DEC4 (Xbox uniquement) | D3DDECLTYPE_DEC3 (Xbox uniquement) | |
XMDECN4 | D3DDECLTYPE_DEC4N (Xbox uniquement) | D3DDECLTYPE_DEC3N (Xbox uniquement) | |
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 (utiliser XMLoadUDecN4_XR et XMStoreUDecN4_XR.) |
XMUDEC4 | D3DDECLTYPE_UDEC4 (Xbox uniquement) D3DDECLTYPE_UDEC3 (Xbox uniquement) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (Xbox uniquement) D3DDECLTYPE_UDEC3N (Xbox uniquement) |
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 uniquement) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
Constantes globales dans la bibliothèque DirectXMath
Pour réduire la taille du segment de données, la bibliothèque DirectXMath utilise la macro XMGLOBALCONST pour utiliser un certain nombre de constantes internes globales dans son implémentation. Par convention, ces constantes globales internes sont préfixées par g_XM. En règle générale, il s’agit de l’un des types suivants : XMVECTORU32, XMVECTORF32 ou XMVECTORI32.
Ces constantes globales internes sont susceptibles de changer dans les révisions futures de la bibliothèque DirectXMath. Utilisez des fonctions publiques qui encapsulent les constantes lorsque cela est possible plutôt que l’utilisation directe de g_XM valeurs globales. Vous pouvez également déclarer vos propres constantes globales à l’aide de XMGLOBALCONST.
Windows SSE et SSE2
Le jeu d’instructions SSE prend uniquement en charge les vecteurs à virgule flottante à précision unique. DirectXMath doit utiliser le jeu d’instructions SSE2 pour fournir la prise en charge des vecteurs entiers. SSE2 est pris en charge par tous les processeurs Intel depuis l’introduction du Pentium 4, de tous les processeurs AMD K8 et versions ultérieures, et de tous les processeurs compatibles x64.
Notes
Windows 8 pour x86 ou version ultérieure nécessite la prise en charge de SSE2. Toutes les versions de Windows x64 nécessitent la prise en charge de SSE2. Windows sur ARM/ARM64 nécessite ARM_NEON.
Variantes de routine
Il existe plusieurs variantes des fonctions DirectXMath qui facilitent l’exécution de votre travail :
- Les fonctions de comparaison permettent de créer des branches conditionnelles complexes basées sur un plus petit nombre d’opérations de comparaison de vecteurs. Le nom de ces fonctions se termine par « R », par exemple XMVector3InBoundsR. Les fonctions retournent un enregistrement de comparaison sous la forme d’une valeur de retour UINT ou d’un paramètre de sortie UINT. Vous pouvez utiliser les macros XMComparision* pour tester la valeur.
- Fonctions batch pour effectuer des opérations de type batch sur des tableaux vectoriels plus volumineux. Le nom de ces fonctions se termine par « Stream », comme XMVector3TransformStream. Les fonctions fonctionnent sur un tableau d’entrées et génèrent un tableau de sorties. En règle générale, ils prennent une foulée d’entrée et de sortie.
- Fonctions d’estimation qui implémentent une estimation plus rapide au lieu d’un résultat plus lent et plus précis. Le nom de ces fonctions se termine par « Est », comme XMVector3NormalizeEst. L’impact sur la qualité et les performances de l’utilisation de l’estimation varie d’une plateforme à l’autre, mais nous vous recommandons d’utiliser des variantes d’estimation pour le code sensible aux performances.
Incohérences de la plateforme
La bibliothèque DirectXMath est destinée à être utilisée dans les applications et jeux graphiques sensibles aux performances. Par conséquent, l’implémentation est conçue pour une vitesse optimale de traitement normal sur toutes les plateformes prises en charge. Les résultats aux conditions limites, en particulier ceux qui génèrent des éléments spéciaux à virgule flottante, sont susceptibles de varier d’une cible à l’autre. Ce comportement dépend également d’autres paramètres d’exécution, tels que le mot de contrôle x87 pour la cible non intrinsèque Windows 32 bits ou le mot de contrôle SSE pour Windows 32 bits et 64 bits. En outre, il y aura des différences dans les conditions limites entre les différents fournisseurs de processeurs.
N’utilisez pas DirectXMath dans des applications scientifiques ou autres où la précision numérique est primordiale. En outre, cette limitation se reflète dans le manque de prise en charge des calculs de précision double ou d’autres calculs de précision étendus.
Notes
Les chemins de code scalaires _XM_NO_INTRINSICS_ sont généralement écrits pour la conformité, et non pour les performances. Leurs résultats de condition de limite varient également.
Extensions spécifiques à la plateforme
La bibliothèque DirectXMath est destinée à simplifier la programmation SIMD C++ offrant une excellente prise en charge des plateformes x86, x64 et Windows RT à l’aide d’instructions intrinsèques largement prises en charge (SSE2 et ARM-NEON).
Toutefois, il arrive parfois que des instructions spécifiques à la plateforme s’avèrent utiles. En raison de la façon dont DirectXMath est implémenté, il est souvent trivial d’utiliser des types DirectXMath directement dans des instructions intrinsèques standard prises en charge par le compilateur et d’utiliser DirectXMath comme chemin d’accès de secours pour les plateformes qui ne prennent pas en charge l’instruction étendue.
Par exemple, voici un exemple simplifié d’utilisation de l’instruction dot-product SSE 4.1. Notez que vous devez protéger explicitement le chemin du code pour éviter de générer des exceptions d’instruction non valides au moment de l’exécution. Assurez-vous que les chemins de code effectuent suffisamment de travail pour justifier le coût supplémentaire de la branche, la complexité de la maintenance de plusieurs chemins de code, et ainsi de suite.
#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;
}
Pour plus d’informations sur les extensions spécifiques à la plateforme, consultez :
DirectXMath : SSE, SSE2 et ARM-NEON
DirectXMath : SSE3 et SSSE3
DirectXMath : SSE4.1 et SSE4.2
DirectXMath : AVX
DirectXMath : F16C et FMA
DirectXMath : AVX2
DirectXMath : ARM64
Rubriques connexes
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour