Partilhar via


Otimização de código com a biblioteca DirectXMath

Este tópico descreve considerações e estratégias de otimização com a Biblioteca DirectXMath.

Use os acessadores com moderação

As operações baseadas em vetores usam os conjuntos de instruções SIMD e estes fazem uso de registros especiais. O acesso a componentes individuais requer a mudança dos registos SIMD para os registos escalares e vice-versa.

Quando possível, é mais eficiente inicializar todos os componentes de um XMVECTOR de uma só vez, em vez de usar uma série de acessadores vetoriais individuais.

Use as configurações de compilação corretas

Para destinos x86 do Windows, habilite /arch:SSE2. Para todos os destinos do Windows, habilite /fp:fast.

Por padrão, a compilação na Biblioteca DirectXMath para destinos x86 do Windows é feita com _XM_SSE_INTRINSICS_ definidos. Isso significa que todas as funcionalidades do DirectXMath usarão instruções SSE2. No entanto, o mesmo não acontece com outros códigos.

O código fora do DirectXMath é tratado usando padrões do compilador. Sem essa opção, o código gerado pode muitas vezes usar o código x87 menos eficiente.

É altamente recomendável que você sempre use a versão mais recente disponível do compilador.

Use as funções Est quando apropriado

Muitas funções têm uma função de estimativa equivalente terminando em Est. Estas funções trocam alguma precisão para melhorar o desempenho. As funções Est são apropriadas para cálculos não críticos, onde a precisão pode ser sacrificada pela velocidade. A quantidade exata de precisão perdida e o aumento de velocidade dependem da plataforma.

Por exemplo, a funçãoXMVector3AngleBetweenNormalsEst pode ser usada no lugar da funçãoXMVector3AngleBetweenNormals.

Usar tipos de dados e operações alinhados

Os conjuntos de instruções SIMD em versões do Windows que suportam SSE2 normalmente têm versões alinhadas e desalinhadas de operações de memória. A utilização das operações alinhadas é mais rápida e deve ser preferida sempre que possível.

A Biblioteca DirectXMath fornece funcionalidade alinhada e não alinhada de acesso por meio de tipos de vetores variantes, estrutura e funções. Estas variantes são indicadas por um "A" no final do nome.

Por exemplo, há uma estrutura XMFLOAT4X4 não alinhada e uma estrutura XMFLOAT4X4A alinhada, que são usadas pelasXMStoreFloat4 e funções XMStoreFloat4A, respectivamente.

Alinhar corretamente as alocações

As versões alinhadas do SSE intrínsecos subjacentes à biblioteca DirectXMath são mais rápidas do que as não alinhadas.

Por esse motivo, as operações DirectXMath usando XMVECTOR e objetos XMMATRIX assumem que esses objetos estão alinhados a 16 bytes. Isso é automático para alocações baseadas em pilha, se o código for compilado na Biblioteca DirectXMath usando as configurações recomendadas do compilador do Windows (consulte Usar configurações corretas de compilação). No entanto, é importante garantir que a alocação de heap contendo XMVECTOR e objetos XMMATRIX, ou moldes para esses tipos, atenda a esses requisitos de alinhamento.

Enquanto as alocações de memória do Windows de 64 bits são alinhadas a 16 bytes, por padrão, nas versões de 32 bits da memória do Windows alocada é de apenas 8 bytes. Para obter informações sobre como controlar o alinhamento da memória, consulte _aligned_malloc.

Ao usar tipos DirectXMath alinhados com a STL (Biblioteca de Modelos Padrão), você precisará fornecer um alocador personalizado que garanta o alinhamento de 16 bytes. Consulte o de blog do Visual C++ Team para obter um exemplo de como escrever um alocador personalizado (em vez de malloc/free, você desejará usar _aligned_malloc e _aligned_free em sua implementação).

Observação

Alguns modelos STL modificam o alinhamento do tipo fornecido. Por exemplo, make_shared<> adiciona algumas informações de rastreamento interno que podem ou não respeitar o alinhamento do tipo de usuário fornecido, resultando em membros de dados desalinhados. Nesse caso, você precisa usar tipos não alinhados em vez de tipos alinhados. Se você derivar de classes existentes, incluindo muitos objetos do Tempo de Execução do Windows, também poderá modificar o alinhamento de uma classe ou estrutura.

 

Evite sobrecargas do operador quando possível

Como um recurso de conveniência, vários tipos, como XMVECTOR e XMMATRIX, têm sobrecargas de operador para operações aritméticas comuns. Tais sobrecargas do operador tendem a criar inúmeros objetos temporários. Recomendamos que você evite essas sobrecargas de operador em código sensível ao desempenho.

Denormais

Para suportar cálculos próximos de 0, o padrão de ponto flutuante IEEE 754 inclui suporte para subfluxo gradual. O fluxo inferior gradual é implementado através do uso de valores desnormalizados, e muitas implementações de hardware são lentas ao lidar com denormais. Uma otimização a considerar é desabilitar a manipulação de denormais para as operações vetoriais usadas pelo DirectXMath.

A alteração do tratamento de denormais é feita usando a rotina de _controlfp_s em uma base pré-thread e pode resultar em melhorias de desempenho. Use este código para alterar a manipulação de denormais:

  #include <float.h>;
    unsigned int control_word;
    _controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );

Observação

Em versões de 64 bits do Windows, instruções de SSE são usadas para todos os cálculos, não apenas para as operações vetoriais. Alterar a manipulação desnormal afeta todos os cálculos de ponto flutuante em seu programa, não apenas as operações vetoriais usadas pelo DirectXMath.

 

Aproveite a dualidade de ponto flutuante inteiro

O DirectXMath suporta vetores de 4 pontos flutuantes de precisão única ou quatro valores de 32 bits (assinados ou não assinados).

Como os conjuntos de instruções usados para implementar a Biblioteca DirectXMath têm a capacidade de tratar os mesmos dados como vários tipos diferentes - por exemplo, tratar o mesmo vetor como dados de ponto flutuante e inteiros - certas otimizações podem ser alcançadas. Você pode obter essas otimizações usando as rotinas de inicialização de vetor inteiro e operadores bit a bit para manipular valores de ponto flutuante.

O formato binário de números de ponto flutuante de precisão única usado pela Biblioteca DirectXMath está completamente em conformidade com o padrão IEEE 754:

     SIGN    EXPONENT   MANTISSA
     X       XXXXXXXX   XXXXXXXXXXXXXXXXXXXXXXX
     1 bit   8 bits     23 bits

Ao trabalhar com o número de ponto flutuante de precisão única IEEE 754, é importante ter em mente que algumas representações têm um significado especial (ou seja, não estão de acordo com a descrição anterior). Os exemplos incluem:

  • Zero positivo é 0
  • Zero negativo é 0x80000000
  • Q_NAN é 07FC0000
  • +INF é 0x7F800000
  • -INF é 0xFF800000

Prefira formulários de modelo

O formulário de modelo existe para XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLefte XMVectorRotateRight. Usando estes em vez da forma de função geral permite que o compilador crie implementações muito mais eficientes. Para SSE , isso geralmente cai para um ou dois valores _mm_shuffle_ps. Para ARM-NEON, o modelo de XMVectorSwizzle pode utilizar vários casos especiais em vez do swizzle/permute VTBL mais geral.

Usando o DirectXMath com o Direct3D

Um uso comum para o DirectXMath é executar cálculos gráficos para uso com o Direct3D. Com o Direct3D 10.x e o Direct3D 11.x, você pode usar a biblioteca DirectXMath das seguintes maneiras diretas:

Guia de programação do DirectXMath