Elementos internos de biblioteca
En este tema se describe el diseño interno de la biblioteca DirectXMath.
- Convenciones de llamada
- Equivalencia de tipos de biblioteca de gráficos
- Constantes globales en la biblioteca DirectXMath
- SSE de Windows frente a SSE2
- Variantes rutinarias
- Incoherencias de plataforma
- Extensiones específicas de la plataforma
- Temas relacionados
Convenciones de llamada
Para mejorar la portabilidad y optimizar el diseño de datos, debe usar las convenciones de llamada adecuadas para cada plataforma compatible con la biblioteca directXMath. En concreto, cuando se pasan objetos XMVECTOR como parámetros, que se definen como alineados en un límite de 16 bytes, hay diferentes conjuntos de requisitos de llamada, según la plataforma de destino:
Para Windows de 32 bits
Para Windows de 32 bits, hay dos convenciones de llamada disponibles para pasar de forma eficaz __m128 valores (que implementa XMVECTOR en esa plataforma). El estándar es __fastcall, que puede pasar los tres primeros valores __m128 (instancias XMVECTOR ) como argumentos a una función en un registro SSE/SSE2 . __fastcall pasa los argumentos restantes a través de la pila.
Los compiladores más recientes de Microsoft Visual Studio admiten una nueva convención de llamada, __vectorcall, que puede pasar hasta seis valores __m128 (instancias XMVECTOR ) como argumentos para una función en un registro SSE/SSE2 . También puede pasar agregados vectoriales heterogéneos (también conocidos como XMMATRIX) a través de registros SSE/SSE2 si hay suficiente espacio.
Para ediciones de 64 bits de Windows
Para Windows de 64 bits, hay dos convenciones de llamada disponibles para pasar de forma eficaz los valores de __m128. El estándar es __fastcall, que pasa todos los valores __m128 de la pila.
Los compiladores de Visual Studio más recientes admiten la convención de llamada de __vectorcall, que puede pasar hasta seis valores de __m128 (instancias XMVECTOR ) como argumentos para una función en un registro SSE/SSE2 . También puede pasar agregados vectoriales heterogéneos (también conocidos como XMMATRIX) a través de registros SSE/SSE2 si hay suficiente espacio.
Para Windows en ARM
Windows en ARM & ARM64 admite pasar los cuatro primeros valores de __n128 (instancias XMVECTOR ) en el registro.
Solución DirectXMath
Los alias FXMVECTOR, GXMVECTOR, HXMVECTOR y CXMVECTOR admiten estas convenciones:
- Use el alias FXMVECTOR para pasar hasta las tres primeras instancias de XMVECTOR usadas como argumentos para una función.
- Use el alias GXMVECTOR para pasar la 4ª instancia de un XMVECTOR que se usa como argumento para una función.
- Use el alias HXMVECTOR para pasar las instancias 5 y 6 de un XMVECTOR que se usa como argumento para una función. Para obtener información sobre consideraciones adicionales, consulte la documentación de __vectorcall.
- Use el alias CXMVECTOR para pasar cualquier otra instancia de XMVECTOR utilizada como argumentos.
Nota
Para los parámetros de salida, use siempre XMVECTOR* o XMVECTOR& y ignorelos con respecto a las reglas anteriores para los parámetros de entrada.
Debido a las limitaciones de __vectorcall, se recomienda no usar GXMVECTOR o HXMVECTOR para constructores de C++. Solo tiene que usar FXMVECTOR para los tres primeros valores XMVECTOR y, a continuación, usar CXMVECTOR para el resto.
Los alias FXMMATRIX y CXMMATRIX ayudan a aprovechar el argumento HVA pasando con __vectorcall.
- Use el alias FXMMATRIX para pasar el primer XMMATRIX como argumento a la función. Esto supone que no tiene más de dos argumentos FXMVECTOR o más de dos argumentos float, double o FXMVECTOR a la "derecha" de la matriz. Para obtener información sobre consideraciones adicionales, consulte la documentación de __vectorcall.
- Use el alias CXMMATRIX de lo contrario.
Debido a las limitaciones de __vectorcall, se recomienda no usar nunca FXMMATRIX para constructores de C++. Simplemente use CXMMATRIX.
Además de los alias de tipo, también debe usar la anotación XM_CALLCONV para asegurarse de que la función usa la convención de llamada adecuada (__fastcall frente a __vectorcall) en función del compilador y la arquitectura. Debido a las limitaciones de __vectorcall, se recomienda no usar XM_CALLCONV para constructores de C++.
A continuación se muestran declaraciones de ejemplo que ilustran esta convención:
XMMATRIX XM_CALLCONV XMMatrixLookAtLH(FXMVECTOR EyePosition, FXMVECTOR FocusPosition, FXMVECTOR UpDirection);
XMMATRIX XM_CALLCONV XMMatrixTransformation2D(FXMVECTOR ScalingOrigin, float ScalingOrientation, FXMVECTOR Scaling, FXMVECTOR RotationOrigin, float Rotation, GXMVECTOR Translation);
void XM_CALLCONV XMVectorSinCos(XMVECTOR* pSin, XMVECTOR* pCos, FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorHermiteV(FXMVECTOR Position0, FXMVECTOR Tangent0, FXMVECTOR Position1, GXMVECTOR Tangent1, HXMVECTOR T);
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3)
XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M);
XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose(FXMMATRIX M1, CXMMATRIX M2);
Para admitir estas convenciones de llamada, estos alias de tipo se definen de la siguiente manera (los parámetros se deben pasar por valor para que el compilador los considere para pasar en el registro):
Para aplicaciones de Windows de 32 bits
Cuando se usa __fastcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Al usar __vectorcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Para aplicaciones windows nativas de 64 bits
Cuando se usa __fastcall:
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Al usar __vectorcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Windows en ARM
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Nota
Aunque todas las funciones se declaran insertadas y, en muchos casos, el compilador no tendrá que usar convenciones de llamada para estas funciones, hay casos en los que el compilador puede decidir que es más eficaz no insertar la función y, en estos casos, queremos la mejor convención de llamada posible para cada plataforma.
Equivalencia de tipos de biblioteca de gráficos
Para admitir el uso de directXMath Library, muchos tipos y estructuras de la biblioteca directXMath son equivalentes a las implementaciones de Windows de los tipos D3DDECLTYPE y D3DFORMAT , así como a los tipos de DXGI_FORMAT .
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (solo Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (solo Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4 | D3DDECLTYPE_DEC4 (solo Xbox) | D3DDECLTYPE_DEC3 (solo Xbox) | |
XMDECN4 | D3DDECLTYPE_DEC4N (solo Xbox) | D3DDECLTYPE_DEC3N (solo Xbox) | |
XMFLOAT2 | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT2A | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT3 | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3A | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3PK | DXGI_FORMAT_R11G11B10_FLOAT | ||
XMFLOAT3SE | DXGI_FORMAT_R9G9B9E5_SHAREDEXP | ||
XMFLOAT4 | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMFLOAT4A | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMHALF2 | D3DDECLTYPE_FLOAT16_2 | D3DFMT_G16R16F | DXGI_FORMAT_R16G16_FLOAT |
XMHALF4 | D3DDECLTYPE_FLOAT16_4 | D3DFMT_A16B16G16R16F | DXGI_FORMAT_R16G16B16A16_FLOAT |
XMINT2 | DXGI_FORMAT_R32G32_SINT | ||
XMINT3 | DXGI_FORMAT_R32G32B32_SINT | ||
XMINT4 | DXGI_FORMAT_R32G32B32A32_SINT | ||
XMSHORT2 | D3DDECLTYPE_SHORT2 | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SINT |
XMSHORTN2 | D3DDECLTYPE_SHORT2N | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SNORM |
XMSHORT4 | D3DDECLTYPE_SHORT4 | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SINT |
XMSHORTN4 | D3DDECLTYPE_SHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SNORM |
XMUBYTE2 | DXGI_FORMAT_R8G8_UINT | ||
XMUBYTEN2 | D3DFMT_A8P8, D3DFMT_A8L8 | DXGI_FORMAT_R8G8_UNORM | |
XMUINT2 | DXGI_FORMAT_R32G32_UINT | ||
XMUINT3 | DXGI_FORMAT_R32G32B32_UINT | ||
XMUINT4 | DXGI_FORMAT_R32G32B32A32_UINT | ||
XMU555 | D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM | |
XMU565 | D3DFMT_R5G6B5 | DXGI_FORMAT_B5G6R5_UNORM | |
XMUBYTE4 | D3DDECLTYPE_UBYTE4 | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UINT |
XMUBYTEN4 | D3DDECLTYPE_UBYTE4N | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UNORM DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM (use XMLoadUDecN4_XR y XMStoreUDecN4_XR). |
XMUDEC4 | D3DDECLTYPE_UDEC4 (solo Xbox) D3DDECLTYPE_UDEC3 (solo Xbox) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (solo Xbox) D3DDECLTYPE_UDEC3N (solo Xbox) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UNORM |
XMUNIBBLE4 | D3DFMT_A4R4G4B4, D3DFMT_X4R4G4B4 | DXGI_FORMAT_B4G4R4A4_UNORM (DXGI 1.2+) | |
XMUSHORT2 | D3DDECLTYPE_USHORT2 | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UINT |
XMUSHORTN2 | D3DDECLTYPE_USHORT2N | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UNORM |
XMUSHORT4 | D3DDECLTYPE_USHORT4 (solo Xbox) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
Constantes globales en la biblioteca DirectXMath
Para reducir el tamaño del segmento de datos, la biblioteca DirectXMath usa la macro XMGLOBALCONST para hacer uso de una serie de constantes internas globales en su implementación. Por convención, estas constantes globales internas tienen el prefijo g_XM. Normalmente, son uno de los siguientes tipos: XMVECTORU32, XMVECTORF32 o XMVECTORI32.
Estas constantes globales internas están sujetas a cambios en futuras revisiones de la biblioteca DirectXMath. Use funciones públicas que encapsulan las constantes siempre que sea posible en lugar de usar directamente g_XM valores globales. También puede declarar sus propias constantes globales mediante XMGLOBALCONST.
SSE de Windows frente a SSE2
El conjunto de instrucciones SSE solo proporciona compatibilidad con vectores de punto flotante de precisión sencilla. DirectXMath debe usar el conjunto de instrucciones SSE2 para proporcionar compatibilidad con vectores enteros. SSE2 es compatible con todos los procesadores Intel desde la introducción de Pentium 4, todos los procesadores AMD K8 y posteriores, y todos los procesadores compatibles con x64.
Nota
Windows 8 para x86 o posterior requiere compatibilidad con SSE2. Todas las versiones de Windows x64 requieren compatibilidad con SSE2. Windows en ARM/ARM64 requiere ARM_NEON.
Variantes rutinarias
Hay varias variantes de las funciones directXMath que facilitan el trabajo:
- Funciones de comparación para crear bifurcaciones condicionales complicadas basadas en un número menor de operaciones de comparación de vectores. El nombre de estas funciones termina en "R", como XMVector3InBoundsR. Las funciones devuelven un registro de comparación como un valor devuelto UINT o como un parámetro de salida de UINT. Puede usar las macros XMComparision* para probar el valor.
- Funciones de batch para realizar operaciones de estilo por lotes en matrices de vectores más grandes. El nombre de estas funciones termina en "Stream", como XMVector3TransformStream. Las funciones funcionan en una matriz de entradas y generan una matriz de salidas. Normalmente, toman un paso de entrada y salida.
- Funciones de estimación que implementan una estimación más rápida en lugar de un resultado más lento y preciso. El nombre de estas funciones termina en "Est", como XMVector3NormalizeEst. El impacto en la calidad y el rendimiento del uso de la estimación varía de la plataforma a la plataforma, pero se recomienda usar variantes de estimación para código sensible al rendimiento.
Incoherencias de la plataforma
La biblioteca DirectXMath está pensada para su uso en aplicaciones y juegos gráficos sensibles al rendimiento. Por lo tanto, la implementación está diseñada para una velocidad óptima que realiza el procesamiento normal en todas las plataformas compatibles. Los resultados en condiciones de límite, especialmente aquellos que generan especiales de punto flotante, pueden variar de destino a destino. Este comportamiento también dependerá de otras opciones de configuración en tiempo de ejecución, como la palabra de control x87 para el destino no intrínseco de Windows 32 bits o la palabra de control SSE para Windows de 32 bits y 64 bits. Además, habrá diferencias en las condiciones de límite entre varios proveedores de CPU.
No use DirectXMath en aplicaciones científicas u otras aplicaciones en las que la precisión numérica sea primordial. Además, esta limitación se refleja en la falta de compatibilidad con cálculos de precisión dobles u otros extendidos.
Nota
Por lo general, las rutas de acceso de código escalares _XM_NO_INTRINSICS_ se escriben para el cumplimiento, no para el rendimiento. Los resultados de la condición de límite también variarán.
Extensiones específicas de la plataforma
La biblioteca DirectXMath está pensada para simplificar la programación SIMD de C++ que proporciona una excelente compatibilidad con las plataformas x86, x64 y Windows RT mediante instrucciones intrínsecas ampliamente compatibles (SSE2 y ARM-NEON).
Sin embargo, hay ocasiones en las que las instrucciones específicas de la plataforma pueden resultar beneficiosas. Debido a la forma en que se implementa DirectXMath, en muchos casos es trivial usar tipos DirectXMath directamente en instrucciones intrínsecas compatibles con el compilador estándar y usar DirectXMath como ruta de acceso de reserva para plataformas que no admiten la instrucción extendida.
Por ejemplo, este es un ejemplo simplificado de aprovechar la instrucción SSE 4.1 dot-product. Tenga en cuenta que debe proteger explícitamente la ruta de acceso de código para evitar generar excepciones de instrucciones no válidas en tiempo de ejecución. Asegúrese de que las rutas de acceso de código realizan un trabajo lo suficientemente significativo como para justificar el costo adicional de la bifurcación, la complejidad del mantenimiento de varias rutas de acceso de código, etc.
#include <Windows.h>
#include <stdio.h>
#include <DirectXMath.h>
#include <intrin.h>
#include <smmintrin.h>
using namespace DirectX;
bool g_bSSE41 = false;
void DetectCPUFeatures()
{
#ifndef _M_ARM
// See __cpuid documentation on MSDN for more information
int CPUInfo[4] = {-1};
#if defined(__clang__) || defined(__GNUC__)
__cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 0);
#endif
if ( CPUInfo[0] >= 1 )
{
#if defined(__clang__) || defined(__GNUC__)
__cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 1);
#endif
if ( CPUInfo[2] & 0x80000 )
g_bSSE41 = true;
}
#endif
}
int main()
{
if ( !XMVerifyCPUSupport() )
return -1;
DetectCPUFeatures();
...
XMVECTORF32 v1 = { 1.f, 2.f, 3.f, 4.f };
XMVECTORF32 v2 = { 5.f, 6.f, 7.f, 8.f };
XMVECTOR r2, r3, r4;
if ( g_bSSE41 )
{
#ifndef _M_ARM
r2 = _mm_dp_ps( v1, v2, 0x3f );
r3 = _mm_dp_ps( v1, v2, 0x7f );
r4 = _mm_dp_ps( v1, v2, 0xff );
#endif
}
else
{
r2 = XMVector2Dot( v1, v2 );
r3 = XMVector3Dot( v1, v2 );
r4 = XMVector4Dot( v1, v2 );
}
...
return 0;
}
Para obtener más información sobre las extensiones específicas de la plataforma, consulta:
DirectXMath: SSE, SSE2 y ARM-NEON
DirectXMath: SSE3 y SSSE3
DirectXMath: SSE4.1 y SSE4.2
DirectXMath: AVX
DirectXMath: F16C y FMA
DirectXMath: AVX2
DirectXMath: ARM64
Temas relacionados
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de