Belső kódtárak
Ez a témakör a DirectXMath-kódtár belső kialakítását ismerteti.
- hívási konvenciók
- grafikus tár típusa egyenértékűségi
- Global Constants a DirectXMath Library
- Windows SSE és SSE2
- Rutinvariánsok
- platform inkonzisztenciája
- platformspecifikus bővítmények
- Kapcsolódó témakörök
Hívási konvenciók
A hordozhatóság javítása és az adatelrendezés optimalizálása érdekében a DirectXMath-kódtár által támogatott platformokhoz a megfelelő hívási konvenciókra van szükség. Pontosabban, ha XMVECTOR objektumokat paraméterekként ad át, amelyek egy 16 bájtos határvonalon vannak meghatározva, a célplatformtól függően különböző hívási követelmények állnak rendelkezésre:
32 bites Windows
A 32 bites Windows esetében két hívási konvenció érhető el a __m128 értékek hatékony átadásához (amely XMVECTOR implementál ezen a platformon). A szabvány az __fastcall, amely az első három __m128 értéket (XMVECTOR-példányokat) argumentumként továbbíthatja egy SSE/SSE2-regiszter egyik függvényéhez. __fastcall a fennmaradó argumentumokat a veremen keresztül adja át.
Az újabb Microsoft Visual Studio-fordítók támogatják az új hívási konvenciót, a __vectorcall, amely legfeljebb hat __m128 értéket (XMVECTOR-példányt) adhat át argumentumként egy SSE/SSE2-regisztráció egyik függvényéhez. Heterogén vektor aggregátumokat (más néven XMMATRIX) is átadhat SSE/SSE2 regisztereken keresztül, ha elegendő hely áll rendelkezésre.
Windows 64 bites kiadásaihoz
A 64 bites Windows esetében két hívási konvenció érhető el __m128 értékek hatékony átadásához. A szabvány __fastcall, amely a verem összes __m128 értékét átadja.
Az újabb Visual Studio-fordítók támogatják a __vectorcall hívási konvenciót, amely legfeljebb hat __m128 értéket (XMVECTOR példányt) adhat át argumentumként egy SSE/SSE2-regisztrációban lévő függvénynek. Heterogén vektor aggregátumokat (más néven XMMATRIX) is átadhat SSE/SSE2 regisztereken keresztül, ha elegendő hely áll rendelkezésre.
Windowshoz ARM-
Az ARM-alapú Windows & ARM64 támogatja az első négy __n128 érték (XMVECTOR példányok) regisztrálását.
DirectXMath-megoldás
A FXMVECTOR, GXMVECTOR, HXMVECTORés CXMVECTOR aliasok támogatják ezeket az egyezményeket:
- Az FXMVECTOR alias használatával adja át a függvény argumentumaként használt XMVECTOR első három példányát.
- A GXMVECTOR alias használatával adja át egy XMVECTOR 4. példányát egy függvény argumentumaként.
- A HXMVECTOR alias használatával adja át egy XMVECTOR argumentumként használt 5. és 6. példányát egy függvénynek. További szempontokról a __vectorcall dokumentációjában talál további információt.
- A CXMVECTOR alias használatával adja át az argumentumként használt XMVECTOR további példányait.
Jegyzet
Kimeneti paraméterek esetén mindig használja az XMVECTOR* vagy az XMVECTOR&, és hagyja figyelmen kívül azokat a bemeneti paraméterek előző szabályaival kapcsolatban.
A __vectorcall korlátozásai miatt javasoljuk, hogy ne használja GXMVECTOR vagy HXMVECTOR C++ konstruktorokhoz. Csak használja FXMVECTOR az első három XMVECTOR értékhez, majd a többihez használja CXMVECTOR.
Az FXMMATRIX és CXMMATRIX aliasok segítenek kihasználni a __vectorcall átadott HVA-argumentum előnyeit.
- Az FXMMATRIX alias használatával adja át az első XMMATRIX argumentumként a függvénynek. Ez azt feltételezi, hogy nem rendelkezik két FXMVECTOR argumentumnál, vagy több mint két lebegőpontos, dupla vagy FXMVECTOR argumentumot a mátrix "jobb oldalán". További szempontokról a __vectorcall dokumentációjában talál további információt.
- Máskülönben használja a CXMMATRIX aliast.
A __vectorcall korlátozásai miatt javasoljuk, hogy a C++ konstruktorokhoz soha ne használjon FXMMATRIX. Csak használja CXMMATRIX.
A típus-aliasok mellett a XM_CALLCONV széljegyzetet is használnia kell, hogy a függvény a fordító és az architektúra alapján a megfelelő hívási konvenciót (__fastcall és __vectorcall) használja-e. A __vectorcall korlátozásai miatt javasoljuk, hogy ne használja a C++ konstruktorokhoz készült XM_CALLCONV.
Az alábbi példadeklarációk szemléltetik ezt az egyezményt:
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);
Ezeknek a hívási konvencióknak a támogatásához ezek a típus-aliasok az alábbiak szerint vannak definiálva (a paramétereket érték szerint kell átadni a fordítónak, hogy figyelembe vehesse őket a regisztráción belüli továbbításhoz):
32 bites Windows-alkalmazásokhoz
A __fastcall használata esetén:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
__vectorcall használata esetén:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
64 bites natív Windows-alkalmazásokhoz
A __fastcall használata esetén:
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
__vectorcall használata esetén:
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 ARM-
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Jegyzet
Bár az összes függvényt beágyazottként deklarálják, és sok esetben a fordítónak nem kell hívási konvenciót használnia ezekhez a függvényekhez, vannak olyan esetek, amikor a fordító úgy dönthet, hogy hatékonyabb, ha nem beágyazotta a függvényt, és ezekben az esetekben a legjobb hívási konvenciót szeretnénk elérni minden platformhoz.
Grafikus tár típusának egyenértékűsége
A DirectXMath-kódtár használatának támogatásához számos DirectXMath-kódtártípus és -struktúra egyenértékű a D3DDECLTYPE és D3DFORMAT windowsos implementációival, valamint a DXGI_FORMAT típusokkal.
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (csak Xbox konzolon) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (csak Xbox konzolon) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4 | D3DDECLTYPE_DEC4 (csak Xbox konzolon) | D3DDECLTYPE_DEC3 (csak Xbox konzolon) | |
XMDECN4 | D3DDECLTYPE_DEC4N (csak Xbox konzolon) | D3DDECLTYPE_DEC3N (csak Xbox konzolon) | |
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 (XMLoadUDecN4_XR és XMStoreUDecN4_XRhasználata.) |
XMUDEC4 | D3DDECLTYPE_UDEC4 (csak Xbox konzolon) D3DDECLTYPE_UDEC3 (csak Xbox konzolon) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (csak Xbox konzolon) D3DDECLTYPE_UDEC3N (csak Xbox konzolon) |
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 (csak Xbox konzolon) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
Globális állandók a DirectXMath könyvtárban
Az adatszegmens méretének csökkentése érdekében a DirectXMath-kódtár a XMGLOBALCONST makrót használja számos globális belső állandó használatára a megvalósítás során. Konvenció szerint az ilyen belső globális állandókat g_XM. Ezek általában a következő típusok egyike: XMVECTORU32, XMVECTORF32vagy XMVECTORI32.
Ezek a belső globális állandók a DirectXMath-kódtár jövőbeli változataiban változhatnak. A g_XM globális értékek közvetlen használata helyett olyan nyilvános függvényeket használjon, amelyek lehetőség szerint belefoglalják az állandókat. Saját globális állandókat is deklarálhat XMGLOBALCONSThasználatával.
Windows SSE és SSE2
Az SSE-utasításkészlet csak egy pontosságú lebegőpontos vektorok számára nyújt támogatást. A DirectXMath-nak az SSE2 utasításkészletet kell használnia az egész számvektor támogatásához. Az SSE2-t minden Intel processzor támogatja a Pentium 4 bevezetése óta, az összes AMD K8 és újabb processzor, valamint az összes x64-kompatibilis processzor.
Jegyzet
Az x86-os vagy újabb Windows 8-hoz az SSE2 támogatása szükséges. A Windows x64 minden verziója SSE2-t igényel. Az ARM/ARM64-alapú Windowshoz ARM_NEON szükséges.
Rutinvariánsok
A DirectXMath függvények számos változata megkönnyíti a munkát:
- Összehasonlító függvények összetett feltételes elágaztatás létrehozásához kisebb számú vektor-összehasonlító művelet alapján. Ezeknek a függvényeknek a neve "R" végződésű, például XMVector3InBoundsR. A függvények egy összehasonlító rekordot ad vissza UINT visszatérési értékként vagy UINT out paraméterként. Az érték teszteléséhez használhatja az XMComparision* makrókat.
- Batch-függvények a nagyobb vektortömbök kötegstílusú műveleteinek végrehajtásához. Ezeknek a függvényeknek a neve "Stream" végződik, például XMVector3TransformStream. A függvények bemenetek tömbjén működnek, és kimenetek tömbje jön létre. Általában bemeneti és kimeneti léptéket vesznek igénybe.
- A lassabb, pontosabb eredmény helyett gyorsabb becslést megvalósító becslési függvények. Ezeknek a függvényeknek a neve "Est" végződik, például XMVector3NormalizeEst. A becslés minőségére és teljesítményére gyakorolt hatás platformonként eltérő, de javasoljuk, hogy a teljesítményérzékeny kódhoz használjon becslési változatokat.
Platform inkonzisztenciák
A DirectXMath kódtár teljesítményérzékeny grafikus alkalmazásokban és játékokban való használatra készült. Ezért az implementáció úgy lett kialakítva, hogy az optimális sebesség érdekében normál feldolgozást végez az összes támogatott platformon. A határfeltételek, különösen a lebegőpontos különlegességeket generáló eredmények valószínűleg céltól célig eltérőek. Ez a viselkedés más futásidejű beállításoktól is függ, például a Windows 32 bites no-intrinsics cél x87 vezérlőszavaitól vagy a Windows 32 bites és 64 bites SSE vezérlőszavaitól. Emellett a különböző processzorgyártók között különbségek lesznek a határfeltételek között.
Ne használja a DirectXMath-ot olyan tudományos vagy egyéb alkalmazásokban, amelyekben a numerikus pontosság a legfontosabb. Ez a korlátozás a dupla vagy más kiterjesztett pontosságú számítások támogatásának hiányában is tükröződik.
Jegyzet
A _XM_NO_INTRINSICS_ skaláris kód elérési útjai általában megfelelőségre, nem teljesítményre vannak megírva. A határfeltételek eredményei is eltérőek lesznek.
Platformspecifikus bővítmények
A DirectXMath kódtár célja, hogy leegyszerűsítse a C++ SIMD-programozást, amely kiváló támogatást nyújt az x86-os, x64-es és Windows RT-platformokhoz széles körben támogatott belső utasítások (SSE2 és ARM-NEON) használatával.
Vannak azonban olyan esetek, amikor a platformspecifikus utasítások előnyösnek bizonyulhatnak. A DirectXMath implementálásának módja miatt sok esetben triviális a DirectXMath-típusok közvetlen használata a standard fordító által támogatott belső utasításokban, valamint a DirectXMath tartalék elérési útja olyan platformok esetében, amelyek nem támogatják a kiterjesztett utasítást.
Íme például egy egyszerűsített példa az SSE 4.1 dot-product utasítás használatára. Vegye figyelembe, hogy a kód elérési útját explicit módon kell őriznie, hogy futásidőben ne generáljon érvénytelen utasításkivételeket. Győződjön meg arról, hogy a kód elérési útjai elég jelentős munkát végeznek az elágaztatás további költségeinek, a több kódútvonal fenntartásának összetettségének és így tovább.
#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;
}
A platformspecifikus bővítményekkel kapcsolatos további információkért lásd:
DirectXMath: SSE, SSE2 és ARM-NEON
DirectXMath: SSE3 és SSSE3
DirectXMath: SSE4.1 és SSE4.2
DirectXMath: AVX
DirectXMath: F16C és FMA
DirectXMath: AVX2
DirectXMath: ARM64