Partager via


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

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 :

Guide de programmation DirectXMath