Kodoptimering med DirectXMath-biblioteket
I det här avsnittet beskrivs optimeringsöverväganden och strategier med DirectXMath-biblioteket.
- Använd accessorer sparsamt
- Använd korrekta kompileringsinställningar
- Använd Est-funktioner när det är lämpligt
- använda justerade datatyper och åtgärder
- justera allokeringarna korrekt
- undvik överbelastning av operatorer när det är möjligt
- Denormals
- dra nytta av
- föredrar mallformulär
- Använder DirectXMath med Direct3D
- Relaterade ämnen
Använda accessorer sparsamt
Vektorbaserade åtgärder använder SIMD-instruktionsuppsättningarna och dessa använder sig av särskilda register. För att komma åt enskilda komponenter måste du flytta från SIMD-registreringarna till de skalära och tillbaka igen.
När det är möjligt är det mer effektivt att initiera alla komponenter i en XMVECTOR- samtidigt i stället för att använda en serie enskilda vektoråtkomster.
Använda rätt kompileringsinställningar
För Windows x86-mål aktiverar du /arch:SSE2. Aktivera /fp:fast för alla Windows-mål.
Som standard görs kompilering mot DirectXMath-biblioteket för windows x86-mål med _XM_SSE_INTRINSICS_ definierat. Det innebär att alla DirectXMath-funktioner använder SSE2-instruktioner. Samma sak gäller dock inte för annan kod.
Kod utanför DirectXMath hanteras med kompilatorstandarder. Utan den här växeln kan den genererade koden ofta använda den mindre effektiva x87-koden.
Vi rekommenderar starkt att du alltid använder den senaste tillgängliga versionen av kompilatorn.
Använd Est-funktioner när det är lämpligt
Många funktioner har en motsvarande uppskattningsfunktion som slutar på Est. Dessa funktioner handlar med viss noggrannhet för bättre prestanda. Est-funktioner är lämpliga för icke-kritiska beräkningar där noggrannhet kan offras för hastighet. Den exakta mängden förlorad noggrannhet och hastighetsökning är plattformsberoende.
Till exempel kan funktionen XMVector3AngleBetweenNormalsEst användas i stället för funktionen XMVector3AngleBetweenNormals.
Använda justerade datatyper och åtgärder
SIMD-instruktionsuppsättningarna på versioner av fönster som stöder SSE2 har vanligtvis justerade och ojusterade versioner av minnesåtgärder. Användningen av de justerade åtgärderna går snabbare och bör föredras där det är möjligt.
DirectXMath-biblioteket ger åtkomstjusterade och ojusterade funktioner via variantvektortyper, struktur och funktioner. Dessa varianter anges med ett "A" i slutet av namnet.
Det finns till exempel en icke-justerad XMFLOAT4X4 struktur och en justerad XMFLOAT4X4A struktur, som används av XMStoreFloat4 respektive XMStoreFloat4A funktioner.
Justera allokeringar korrekt
De justerade versionerna av SSE inbyggda funktioner som ligger till grund för DirectXMath-biblioteket är snabbare än de ojusterade.
Därför förutsätter DirectXMath-åtgärder som använder XMVECTOR- och XMMATRIX objekt att dessa objekt är 16 byte justerade. Detta är automatiskt för stackbaserade allokeringar, om kod kompileras mot DirectXMath-biblioteket med hjälp av det rekommenderade Windows (se Använd korrekta kompileringsinställningar) kompileringsinställningar. Det är dock viktigt att se till att heap-allokering som innehåller XMVECTOR- och XMMATRIX- objekt, eller gjuts till dessa typer, uppfyller dessa justeringskrav.
64-bitars Windows-minnesallokeringar är 16 byte justerade, men som standard på 32 bitars versioner av Allokerat Windows-minne är endast 8 byte justerat. Information om hur du styr minnesjustering finns i _aligned_malloc.
När du använder justerade DirectXMath-typer med Standard Template Library (STL) måste du ange en anpassad allokering som säkerställer justeringen på 16 byte. Mer information om hur du skriver en anpassad allokering (i stället för malloc/free) finns i blogg för Visual C++ Team . Du vill använda _aligned_malloc och _aligned_free i implementeringen).
Not
Vissa STL-mallar ändrar den angivna typens justering. Till exempel lägger make_shared<> till viss intern spårningsinformation som kanske eller kanske inte respekterar justeringen av den angivna användartypen, vilket resulterar i ojusterade datamedlemmar. I det här fallet måste du använda ojusterade typer i stället för justerade typer. Om du härleder från befintliga klasser, inklusive många Windows Runtime-objekt, kan du också ändra justeringen för en klass eller struktur.
Undvik operatörsöverbelastningar när det är möjligt
Som en bekvämlighetsfunktion har ett antal typer, till exempel XMVECTOR- och XMMATRIX operatoröverbelastningar för vanliga aritmetiska åtgärder. Sådana överlagringar av operatorer tenderar att skapa många temporära objekt. Vi rekommenderar att du undviker dessa operatörsöverbelastningar i prestandakänslig kod.
Avnormals
För att stödja beräkningar nära 0 innehåller IEEE 754-float-point-standarden stöd för gradvis underflöde. Gradvis underflöde implementeras med hjälp av avnormaliserade värden, och många maskinvaruimplementeringar är långsamma vid hantering av denormala värden. En optimering att tänka på är att inaktivera hanteringen av denormal för de vektoråtgärder som används av DirectXMath.
Att ändra hanteringen av denormal görs med hjälp av _controlfp_s rutin på förtrådsbasis och kan resultera i prestandaförbättringar. Använd den här koden för att ändra hanteringen av denormal:
#include <float.h>;
unsigned int control_word;
_controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
Not
I 64-bitarsversioner av Windows används SSE- instruktioner för alla beräkningar, inte bara vektoråtgärderna. Om du ändrar denormal hanteringen påverkas alla flyttalsberäkningar i programmet, inte bara de vektoråtgärder som används av DirectXMath.
Dra nytta av heltals-flyttalsdubblalitet
DirectXMath stöder vektorer med 4 flyttal med enkel precision eller fyra 32-bitarsvärden (signerade eller osignerade).
Eftersom de instruktionsuppsättningar som används för att implementera DirectXMath-biblioteket har möjlighet att behandla samma data som flera olika typer, kan du till exempel behandla samma vektor som dataoptimeringar med flyttals- och heltalsdata. Du kan få dessa optimeringar genom att använda heltalsvektorinitieringsrutiner och bitvisa operatorer för att manipulera flyttalsvärden.
Det binära formatet för flyttalsnummer med enkel precision som används av DirectXMath-biblioteket överensstämmer helt med IEEE 754-standarden:
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
När du arbetar med flyttalsnumret IEEE 754 med enkel precision är det viktigt att komma ihåg att vissa representationer har en särskild betydelse (det vill säga att de inte överensstämmer med föregående beskrivning). Exempel är:
- Positiv nolla är 0
- Negativ nolla är 0x80000000
- Q_NAN är 07FC0000
- +INF är 0x7F800000
- -INF är 0xFF800000
Föredrar mallformulär
Mallformulär finns för XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLeftoch XMVectorRotateRight. Om du använder dessa i stället för det allmänna funktionsformuläret kan kompilatorn skapa mycket mer effektiva implementeringar. För SSE-komprimeras detta ofta ned till ett eller två _mm_shuffle_ps värden. För ARM-NEON kan XMVectorSwizzle mall använda ett antal specialfall snarare än den mer allmänna VTBL swizzle/permute.
Använda DirectXMath med Direct3D
En vanlig användning för DirectXMath är att utföra grafikberäkningar för användning med Direct3D. Med Direct3D 10.x och Direct3D 11.x kan du använda DirectXMath-biblioteket på följande direkta sätt:
Använd namnområdet Färger konstanter direkt i parametern ColorRGBA i ett anrop till parametern ID3D11DeviceContext::ClearRenderTargetView eller ID3D10Device::ClearRenderTargetView-metod. För Direct3D 9 måste du konvertera till XMCOLOR- typ för att använda den som parametern Color i ett anrop till metoden IDirect3DDevice9::Clear.
Använd typerna XMFLOAT4/XMVECTOR och XMFLOAT4X4/XMMATRIX för att konfigurera konstanta buffertstrukturer som referens av HLSL float4 eller matris/float4x4-typer.
Not
XMFLOAT4X4/XMMATRIX typerna är i rad-större format. Om du använder kompileringsväxeln /Zpr (D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR kompileringsflagga) eller utelämnar nyckelordet row_major när du deklarerar matristypen i HLSL, måste du därför transponera matrisen när du ställer in den i den konstanta bufferten.
Med Direct3D 10.x och Direct3D 11.x kan du anta att pekaren som returneras av metoden Map (till exempel ID3D11DeviceContext::Map) i pData member (D3D10_MAPPED_TEXTURE2D.pData, D3D10_MAPPED_TEXTURE3D.pDataeller D3D11_MAPPED_SUBRESOURCE.pData) är 16 byte justerad om du använder funktionsnivå 10_0 eller senare eller när du använder D3D11_USAGE_STAGING resurser.