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 des accesseurs avec parcimonie

Les opérations basées sur des vecteurs utilisent les jeux d’instructions SIMD et utilisent des registres spéciaux. L’accès à des composants individuels nécessite de passer des registres SIMD aux registres scalaires et à 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 x86 de fenêtre est effectuée avec _XM_SSE_INTRINSICS_ défini. Cela signifie que toutes les fonctionnalités DirectXMath utilisent des instructions SSE2. Toutefois, la même chose n’est pas vraie 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 moins efficace.

Nous vous recommandons vivement d’utiliser toujours la dernière version disponible du compilateur.

Utiliser les fonctions Est si nécessaire

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 d’augmentation de vitesse dépend de la plateforme.

Par exemple, la fonction XMVector3AngleBetweenNormalsEst peut être utilisée à la place de la fonction XMVector3AngleBetweenNormals.

Utiliser des types de données et des opérations alignés

Les ensembles 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 préférable dans la mesure du possible.

La bibliothèque DirectXMath fournit des fonctionnalité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ée, qui sont utilisées respectivement par les fonctions XMStoreFloat4 et XMStoreFloat4A.

Aligner correctement les allocations

Les versions alignées de la SSE intrinsèques sous-jacentes à la bibliothèque DirectXMath sont plus rapides que celles non alignées.

Pour cette raison, les opérations DirectXMath utilisant XMVECTOR et objets 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 de 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 XMVECTOR et objets XMMATRIX, ou des casts vers ces types, répondent à ces exigences d’alignement.

Bien que les allocations de mémoire Windows 64 bits soient alignées sur 16 octets, par défaut, les versions 32 bits de la mémoire Windows allouées ne sont alignées 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 de 16 octets. Consultez le blog 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).

Note

Certains modèles STL modifient l’alignement du type fourni. Par exemple, make_shared<> ajoute des informations de suivi internes qui peuvent ou ne pas respecter 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 plutôt que des 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 des opérateurs 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.

Dénormals

Pour prendre en charge les calculs proches de 0, la norme à virgule flottante IEEE 754 inclut la prise en charge du sous-flux progressif. Le sous-flux progressif est implémenté par le biais de l’utilisation de valeurs dénormalisées, et de nombreuses implémentations matérielles sont lentes lors de la gestion des dénormales. 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 de _controlfp_s sur une base de 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 );

Note

Sur les versions 64 bits de Windows, instructions de 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 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 que plusieurs types différents, par exemple, traiter le même vecteur que les optimisations à virgule flottante et aux 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 de bits pour manipuler des valeurs à virgule flottante.

Le format binaire des nombres à virgule flottante simple précision utilisés 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 utilisez le numéro à virgule flottante de précision unique 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 égal à 0
  • Zéro négatif est 0x80000000
  • Q_NAN est 07FC0000
  • +INF est 0x7F800000
  • -INF est 0xFF800000

Préférer les formulaires de modèle

Le formulaire de modèle existe pour XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLeftet 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 efficentes. Pour SSE, cela se 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 modèle VTBL swizzle/permute plus général.

Utilisation de DirectXMath avec Direct3D

Une utilisation courante pour 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 ces manières directes :

Guide de programmation DirectXMath