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 de manière éparse
- Utiliser les paramètres de compilation corrects
- Utiliser les fonctions Est lorsque la appropriée
- utiliser des types de données alignés et des opérations
- aligner correctement les allocations
- Éviter les surcharges des opérateurs lorsque cela est possible
- denormals
- 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 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 :
Utilisez l’espace de noms Colors constantes directement dans le paramètre ColorRGBA dans un appel à la méthode ID3D11DeviceContext ::ClearRenderTargetView ou ID3D10Device ::ClearRenderTargetView méthode. Pour Direct3D 9, vous devez convertir le typeXMCOLORpour 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 HLSL des types float4 ou matrice/float4x4.
Note
XMFLOAT4X4/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 omettez le mot clé row_major lorsque vous déclarez le type de matrice dans HLSL, vous devez transposer la matrice lorsque vous la 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.pDataou D3D11_MAPPED_SUBRESOURCE.pData) est aligné sur 16 octets si vous utilisez niveau de fonctionnalité 10_0 ou version ultérieure ou chaque fois que vous utilisez des ressources D3D11_USAGE_STAGING.