Interne bibliotheek
In dit onderwerp wordt het interne ontwerp van de DirectXMath-bibliotheek beschreven.
- oproepconventies
- equivalentie van het type grafische bibliotheek
- globale constanten in de DirectXMath-bibliotheek
- Windows SSE versus SSE2
- routinevarianten
- platformconsistentie
- platformspecifieke extensies
- Verwante onderwerpen
Oproepconventies
Als u de draagbaarheid wilt verbeteren en de gegevensindeling wilt optimaliseren, moet u de juiste aanroepende conventies gebruiken voor elk platform dat wordt ondersteund door de DirectXMath-bibliotheek. Wanneer u XMVECTOR objecten doorgeeft als parameters, die zijn gedefinieerd als uitgelijnd op een grens van 16 byte, zijn er verschillende reeksen aan oproepvereisten, afhankelijk van het doelplatform:
voor 32-bits Windows-
Voor 32-bits Windows zijn er twee aanroepende conventies beschikbaar voor het efficiënt doorgeven van __m128 waarden (waarmee XMVECTOR- op dat platform wordt geïmplementeerd). De standaard is __fastcall, die de eerste drie __m128 waarden (XMVECTOR instanties) als argumenten kan doorgeven aan een functie in een SSE/SSE2 register. __fastcall resterende argumenten doorgeeft via de stack.
Nieuwere Microsoft Visual Studio-compilers ondersteunen een nieuwe aanroepconventie, __vectorcall, die maximaal zes __m128 waarden (XMVECTOR exemplaren) als argumenten voor een functie in een SSE/SSE2 registreren. Het kan ook heterogene vectoraggregaties (ook wel bekend als XMMATRIX) doorgeven via SSE/SSE2 registers als er voldoende ruimte is.
Voor 64-bits edities van Windows
Voor 64-bits Windows zijn er twee aanroepende conventies beschikbaar voor het efficiënt doorgeven van __m128 waarden. De standaard is __fastcall, die alle __m128 waarden op de stack doorgeeft.
Nieuwere Visual Studio-compilers ondersteunen de __vectorcall aanroepconventie, die maximaal zes __m128 waarden (XMVECTOR instanties) als argumenten voor een functie in een SSE/SSE2 register kan doorgeven. Het kan ook heterogene vectoraggregaties (ook wel bekend als XMMATRIX) doorgeven via SSE/SSE2 registers als er voldoende ruimte is.
voor Windows op ARM-
Windows op ARM & ARM64 ondersteunt het doorgeven van de eerste vier __n128 waarden (XMVECTOR exemplaren) in het register.
DirectXMath-oplossing
De FXMVECTOR, GXMVECTOR, HXMVECTORen CXMVECTOR aliassen ondersteunen deze conventies:
- Gebruik de FXMVECTOR alias om de eerste drie exemplaren van XMVECTOR als argumenten voor een functie door te geven.
- Gebruik de GXMVECTOR alias om het vierde exemplaar van een XMVECTOR door te geven gebruikt als argument voor een functie.
- Gebruik de HXMVECTOR alias om de 5e en 6e instantie van een XMVECTOR- als argument voor een functie door te geven. Zie de __vectorcall documentatie voor meer informatie over aanvullende overwegingen.
- Gebruik de CXMVECTOR alias om eventuele andere exemplaren van XMVECTOR door te geven gebruikt als argumenten.
Notitie
Voor uitvoerparameters gebruikt u altijd XMVECTOR* of XMVECTOR& en negeert u deze met betrekking tot de voorgaande regels voor invoerparameters.
Vanwege beperkingen met __vectorcall raden we u aan geen GXMVECTOR- of HXMVECTOR- te gebruiken voor C++-constructors. Gebruik FXMVECTOR- voor de eerste drie XMVECTOR-waarden en gebruik vervolgens CXMVECTOR- voor de rest.
De FXMMATRIX- en CXMMATRIX aliassen helpen bij het gebruik van het HVA-argument dat wordt doorgegeven met __vectorcall.
- Gebruik de FXMMATRIX alias om de eerste XMMATRIX- als argument door te geven aan de functie. Hierbij wordt ervan uitgegaan dat u niet meer dan twee FXMVECTOR-argumenten hebt of meer dan twee float-, dubbele of FXMVECTOR-argumenten argumenten rechts van de matrix. Zie de __vectorcall documentatie voor meer informatie over aanvullende overwegingen.
- Gebruik anders de CXMMATRIX alias.
Vanwege beperkingen met __vectorcall raden we u aan nooit FXMMATRIX- te gebruiken voor C++-constructors. Gebruik CXMMATRIX.
Naast de typealiassen moet u ook de XM_CALLCONV aantekening gebruiken om ervoor te zorgen dat de functie gebruikmaakt van de juiste aanroepconventie (__fastcall versus __vectorcall) op basis van uw compiler en architectuur. Vanwege beperkingen met __vectorcall raden we u aan geen XM_CALLCONV te gebruiken voor C++-constructors.
Hier volgen voorbeelden van declaraties die deze conventie illustreren:
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);
Ter ondersteuning van deze aanroepende conventies worden deze typealiassen als volgt gedefinieerd (parameters moeten worden doorgegeven door de compiler om deze te overwegen voor in-register-passing):
Voor 32-bits Windows-apps
Wanneer u __fastcall gebruikt:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Wanneer u __vectorcall gebruikt:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Voor 64-bits systeemeigen Windows-apps
Wanneer u __fastcall gebruikt:
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Wanneer u __vectorcall gebruikt:
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 op ARM-
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Notitie
Hoewel alle functies inline worden gedeclareerd en in veel gevallen hoeft de compiler geen aanroepende conventies voor deze functies te gebruiken, zijn er gevallen waarin de compiler kan besluiten dat het efficiënter is om de functie niet inline te plaatsen en in deze gevallen willen we de best mogelijke aanroepconventie voor elk platform.
Equivalentie van grafische bibliotheektypen
Ter ondersteuning van het gebruik van de DirectXMath-bibliotheek zijn veel DirectXMath-bibliotheektypen en -structuren gelijk aan de Windows-implementaties van de D3DDECLTYPE- en D3DFORMAT-typen, evenals de DXGI_FORMAT-typen.
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (alleen Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (alleen Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR- | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4- | D3DDECLTYPE_DEC4 (alleen Xbox) | D3DDECLTYPE_DEC3 (alleen Xbox) | |
XMDECN4 | D3DDECLTYPE_DEC4N (alleen Xbox) | D3DDECLTYPE_DEC3N (alleen 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 (gebruik XMLoadUDecN4_XR en XMStoreUDecN4_XR.) |
XMUDEC4 | D3DDECLTYPE_UDEC4 (alleen Xbox) D3DDECLTYPE_UDEC3 (alleen Xbox) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (alleen Xbox) D3DDECLTYPE_UDEC3N (alleen 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 (alleen Xbox) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
Globale constanten in de DirectXMath-bibliotheek
Om de grootte van het gegevenssegment te verkleinen, gebruikt de DirectXMath-bibliotheek de XMGLOBALCONST macro om gebruik te maken van een aantal globale interne constanten in de implementatie. Volgens de conventie worden dergelijke interne globale constanten voorafgegaan door g_XM. Meestal zijn ze een van de volgende typen: XMVECTORU32, XMVECTORF32of XMVECTORI32.
Deze interne globale constanten zijn onderhevig aan wijzigingen in toekomstige revisies van de DirectXMath-bibliotheek. Gebruik openbare functies die de constanten inkapselen indien mogelijk in plaats van direct gebruik te maken van g_XM globale waarden. U kunt ook uw eigen globale constanten declareren met behulp van XMGLOBALCONST.
Windows SSE versus SSE2
De SSE-instructieset biedt alleen ondersteuning voor drijvendekommagectors met één precisie. DirectXMath moet gebruikmaken van de SSE2-instructieset om vectorondersteuning voor gehele getallen te bieden. SSE2 wordt ondersteund door alle Intel-processors sinds de introductie van de Pentium 4, alle AMD K8- en latere processors en alle x64-compatibele processors.
Notitie
Windows 8 voor x86 of hoger vereist ondersteuning voor SSE2. Voor alle versies van Windows x64 is ondersteuning vereist voor SSE2. Windows op ARM/ARM64 vereist ARM_NEON.
Routinevarianten
Er zijn verschillende varianten van DirectXMath-functies waarmee u uw werk eenvoudiger kunt doen:
- Vergelijkingsfuncties voor het maken van gecompliceerde voorwaardelijke vertakkingen op basis van een kleiner aantal vectorvergelijkingsbewerkingen. De naam van deze functies eindigt op R, zoals XMVector3InBoundsR. De functies retourneren een vergelijkingsrecord als een UINT-retourwaarde of als een UINT-outparameter. U kunt de XMComparision* macro's gebruiken om de waarde te testen.
- Batch-functies voor het uitvoeren van batchbewerkingen op grotere vectormatrices. De naam van deze functies eindigt op 'Stream' zoals XMVector3TransformStream. De functies werken op een matrix met invoer en genereren een matrix met uitvoer. Normaal gesproken nemen ze een invoer- en uitvoer-stride.
- Schattingsfuncties die een snellere schatting implementeren in plaats van een langzamer, nauwkeuriger resultaat. De naam van deze functies eindigt in 'Est' zoals XMVector3NormalizeEst. De impact op kwaliteit en prestaties van het gebruik van schattingen verschilt van platform tot platform, maar we raden u aan schattingsvarianten te gebruiken voor prestatiegevoelige code.
Inconsistenties van platformen
De DirectXMath-bibliotheek is bedoeld voor gebruik in prestatiegevoelige grafische toepassingen en games. Daarom is de implementatie ontworpen voor optimale snelheid die normale verwerking uitvoert op alle ondersteunde platforms. Resultaten bij grensvoorwaarden, met name de resultaten die speciale drijvende komma's genereren, verschillen waarschijnlijk van doel tot doel. Dit gedrag is ook afhankelijk van andere runtime-instellingen, zoals het x87-besturingselementwoord voor het Windows 32-bits no-intrinsieke doel of het SSE-besturingselementwoord voor zowel Windows 32-bits als 64-bits. Bovendien zijn er verschillen in grensvoorwaarden tussen verschillende CPU-leveranciers.
Gebruik DirectXMath niet in wetenschappelijke of andere toepassingen waarbij numerieke nauwkeurigheid van het grootste belang is. Deze beperking wordt ook weerspiegeld in het gebrek aan ondersteuning voor dubbele of andere uitgebreide precisieberekeningen.
Notitie
De _XM_NO_INTRINSICS_ scalaire codepaden worden over het algemeen geschreven voor naleving, niet voor prestaties. De resultaten van hun grensvoorwaarde verschillen ook.
Platformspecifieke extensies
De DirectXMath-bibliotheek is bedoeld om het programmeren met C++ SIMD te vereenvoudigen en biedt uitstekende ondersteuning voor x86-, x64- en Windows RT-platforms met behulp van intrinsiek instructies (SSE2 en ARM-NEON).
Er zijn echter momenten waarop platformspecifieke instructies nuttig kunnen zijn. Vanwege de manier waarop DirectXMath wordt geïmplementeerd, is het in veel gevallen triviaal om DirectXMath-typen rechtstreeks te gebruiken in standaard-compiler ondersteunde intrinsieke instructies en om DirectXMath te gebruiken als het terugvalpad voor platforms die de uitgebreide instructie niet ondersteunen.
Hier volgt bijvoorbeeld een vereenvoudigd voorbeeld van het gebruik van de SSE 4.1 dot-productinstructie. Houd er rekening mee dat u het codepad expliciet moet bewaken om te voorkomen dat er tijdens runtime ongeldige instructie-uitzonderingen worden gegenereerd. Zorg ervoor dat de codepaden aanzienlijk genoeg werk doen om de extra kosten van vertakkingen, complexiteit van het onderhouden van meerdere codepaden, enzovoort te rechtvaardigen.
#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 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;
}
Zie voor meer informatie over platformspecifieke extensies:
DirectXMath: SSE, SSE2 en ARM-NEON
DirectXMath: SSE3 en SSSE3
DirectXMath: SSE4.1 en SSE4.2
DirectXMath: AVX-
DirectXMath: F16C en FMA-
DirectXMath: AVX2
DirectXMath: ARM64-