Optimisation du code avec la bibliothèque DirectXMath
Cette rubrique décrit les considérations et stratégies d’optimisation avec la bibliothèque DirectXMath.
- Utiliser les accesseurs avec parcimonie
- Utiliser les paramètres de compilation corrects
- Utiliser les fonctions Est le cas échéant
- Utiliser des opérations et des types de données alignés
- Aligner correctement les allocations
- Éviter les surcharges d’opérateur lorsque cela est possible
- Nombres dénormalisés
- Tirer parti de la dualité à virgule flottante entière
- Préférer les formulaires de modèle
- Utilisation de DirectXMath avec Direct3D
- Rubriques connexes
Utiliser les accesseurs avec parcimonie
Les opérations basées sur des vecteurs utilisent les jeux d’instructions SIMD et ceux-ci utilisent des registres spéciaux. L’accès à des composants individuels nécessite de passer des registres SIMD aux registres scalaires, puis de revenir à nouveau.
Dans la mesure du possible, il est plus efficace d’initialiser tous les composants d’un XMVECTOR à la fois, au lieu d’utiliser une série d’accesseurs vectoriels individuels.
Utiliser les paramètres de compilation corrects
Pour les cibles Windows x86, activez /arch:SSE2. Pour toutes les cibles Windows, activez /fp:fast.
Par défaut, la compilation sur la bibliothèque DirectXMath pour les cibles Window x86 s’effectue avec _XM_SSE_INTRINSICS_ défini. Cela signifie que toutes les fonctionnalités DirectXMath utilisent les instructions SSE2. Toutefois, il n’en va pas de même pour d’autres codes.
Le code en dehors de DirectXMath est géré à l’aide des valeurs par défaut du compilateur. Sans ce commutateur, le code généré peut souvent utiliser le code x87 le moins efficace.
Nous vous recommandons vivement de toujours utiliser la dernière version disponible du compilateur.
Utiliser les fonctions Est le cas échéant
De nombreuses fonctions ont une fonction d’estimation équivalente se terminant par Est. Ces fonctions échangent une certaine précision pour améliorer les performances. Les fonctions Est sont appropriées pour les calculs non critiques où la précision peut être sacrifiée pour la vitesse. La quantité exacte de précision perdue et l’augmentation de vitesse dépendent de la plateforme.
Par exemple, la fonction XMVector3AngleBetweenNormalsEst peut être utilisée à la place de la fonction XMVector3AngleBetweenNormals .
Utiliser des opérations et des types de données alignés
Les jeux d’instructions SIMD sur les versions de Windows prenant en charge SSE2 ont généralement des versions alignées et non alignées des opérations de mémoire. L’utilisation des opérations alignées est plus rapide et doit être recommandée dans la mesure du possible.
La bibliothèque DirectXMath fournit des fonctionnalités d’accès alignées et non alignées via des types de vecteurs variants, une structure et des fonctions. Ces variantes sont indiquées par un « A » à la fin du nom.
Par exemple, il existe une structure XMFLOAT4X4 non alignée et une structure XMFLOAT4X4A alignées, qui sont utilisées respectivement par les fonctions XMStoreFloat4 et XMStoreFloat4A .
Aligner correctement les allocations
Les versions alignées des intrinsèques SSE sous-jacentes à la bibliothèque DirectXMath sont plus rapides que les versions non alignées.
Pour cette raison, les opérations DirectXMath utilisant des objets XMVECTOR et XMMATRIX supposent que ces objets sont alignés sur 16 octets. Cela est automatique pour les allocations basées sur la pile, si le code est compilé sur la bibliothèque DirectXMath à l’aide des paramètres du compilateur Windows recommandés (voir Utiliser les paramètres de compilation corrects). Toutefois, il est important de s’assurer que l’allocation de tas contenant des objets XMVECTOR et XMMATRIX , ou des casts en ces types, répond à ces exigences d’alignement.
Alors que les allocations de mémoire Windows 64 bits sont alignées sur 16 octets, par défaut sur les versions 32 bits de la mémoire Windows allouées n’est alignée que sur 8 octets. Pour plus d’informations sur le contrôle de l’alignement de la mémoire, consultez _aligned_malloc.
Lorsque vous utilisez des types DirectXMath alignés avec la bibliothèque de modèles standard (STL), vous devez fournir un allocateur personnalisé qui garantit l’alignement sur 16 octets. Consultez le blog de l’équipe Visual C++ pour obtenir un exemple d’écriture d’un allocateur personnalisé (au lieu de malloc/free, vous voudrez utiliser _aligned_malloc et _aligned_free dans votre implémentation).
Notes
Certains modèles STL modifient l’alignement du type fourni. Par exemple, make_shared<> ajoute des informations de suivi interne qui peuvent respecter ou non l’alignement du type d’utilisateur fourni, ce qui entraîne des membres de données non alignés. Dans ce cas, vous devez utiliser des types non alignés au lieu de types alignés. Si vous dérivez de classes existantes, y compris de nombreux objets Windows Runtime, vous pouvez également modifier l’alignement d’une classe ou d’une structure.
Éviter les surcharges d’opérateur lorsque cela est possible
En guise de fonctionnalité pratique, un certain nombre de types tels que XMVECTOR et XMMATRIX ont des surcharges d’opérateur pour les opérations arithmétiques courantes. Ces surcharges d’opérateur ont tendance à créer de nombreux objets temporaires. Nous vous recommandons d’éviter ces surcharges d’opérateur dans le code sensible aux performances.
Nombres dénormalisés
Pour prendre en charge des calculs proches de 0, la norme de virgule flottante IEEE 754 prend en charge le sous-débit progressif. Le sous-débit progressif est implémenté via l’utilisation de valeurs dénormalisées, et de nombreuses implémentations matérielles sont lentes lors de la gestion des dénormals. Une optimisation à prendre en compte consiste à désactiver la gestion des dénormals pour les opérations vectorielles utilisées par DirectXMath.
La modification de la gestion des dénormals est effectuée à l’aide de la routine _controlfp_s sur une base pré-thread, et peut entraîner des améliorations des performances. Utilisez ce code pour modifier la gestion des dénormals :
#include <float.h>;
unsigned int control_word;
_controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
Notes
Sur les versions 64 bits de Windows, les instructions SSE sont utilisées pour tous les calculs, pas seulement pour les opérations vectorielles. La modification de la gestion dénormale affecte tous les calculs à virgule flottante dans votre programme, pas seulement les opérations vectorielles utilisées par DirectXMath.
Tirer parti de la dualité à virgule flottante entière
DirectXMath prend en charge les vecteurs de 4 valeurs à virgule flottante simple précision ou de quatre valeurs 32 bits (signées ou non signées).
Étant donné que les jeux d’instructions utilisés pour implémenter la bibliothèque DirectXMath ont la possibilité de traiter les mêmes données comme plusieurs types différents, par exemple, traiter le même vecteur comme des données à virgule flottante et des données entières, certaines optimisations peuvent être obtenues. Vous pouvez obtenir ces optimisations à l’aide des routines d’initialisation de vecteurs entiers et des opérateurs en bits pour manipuler des valeurs à virgule flottante.
Le format binaire des nombres à virgule flottante simple précision utilisé par la bibliothèque DirectXMath est entièrement conforme à la norme IEEE 754 :
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
Lorsque vous travaillez avec le nombre à virgule flottante unique précision IEEE 754, il est important de garder à l’esprit que certaines représentations ont une signification particulière (autrement dit, elles ne sont pas conformes à la description précédente). Voici quelques exemples :
- Zéro positif est 0
- Le zéro négatif est 0x80000000
- Q_NAN est 07FC00000
- +INF est 0x7F800000
- -INF est 0xFF800000
Préférer les formulaires de modèle
Un formulaire de modèle existe pour XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLeft et XMVectorRotateRight. L’utilisation de ces éléments au lieu du formulaire de fonction général permet au compilateur de créer des implémentations beaucoup plus efficaces. Pour SSE, cela réduit souvent à une ou deux valeurs _mm_shuffle_ps. Pour ARM-NEON, le modèle XMVectorSwizzle peut utiliser un certain nombre de cas spéciaux plutôt que le VTBL plus général swizzle/permute.
Utilisation de DirectXMath avec Direct3D
Une utilisation courante de DirectXMath consiste à effectuer des calculs graphiques à utiliser avec Direct3D. Avec Direct3D 10.x et Direct3D 11.x, vous pouvez utiliser la bibliothèque DirectXMath de manière directe :
Utilisez les constantes d’espace de noms Colors directement dans le paramètre ColorRGBA dans un appel à la méthode ID3D11DeviceContext::ClearRenderTargetView ou ID3D10Device::ClearRenderTargetView . Pour Direct3D 9, vous devez convertir en type XMCOLOR pour l’utiliser comme paramètre Color dans un appel à la méthode IDirect3DDevice9::Clear .
Utilisez les types XMFLOAT4/XMVECTOR et XMFLOAT4X4/XMMATRIX pour configurer des structures de mémoire tampon constantes pour référence par les types HLSL float4 ou matrix/float4x4.
Notes
XMFLOAT4X4/Les types XMMATRIX sont au format principal de ligne. Par conséquent, si vous utilisez le commutateur du compilateur /Zpr (l’indicateur de compilation D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR) ou si vous omettez l’row_major mot clé lorsque vous déclarez le type de matrice dans HLSL, vous devez transposer la matrice lorsque vous le définissez dans la mémoire tampon constante.
Avec Direct3D 10.x et Direct3D 11.x, vous pouvez supposer que le pointeur retourné par la méthode Map (par exemple, ID3D11DeviceContext::Map) dans le membre pData (D3D10_MAPPED_TEXTURE2D).pData, D3D10_MAPPED_TEXTURE3D. pData ou D3D11_MAPPED_SUBRESOURCE. pData) est aligné sur 16 octets si vous utilisez le niveau de fonctionnalité 10_0 ou supérieur ou chaque fois que vous utilisez D3D11_USAGE_STAGING ressources.