DirectXMath 라이브러리를 통해 코드 최적화
이 항목에서는 DirectXMath 라이브러리를 사용한 최적화 고려 사항 및 전략에 대해 설명합니다.
- 접근자를 아끼는 용도로 사용
- 올바른 컴파일 설정 사용
- 적절한 경우 Est 함수 사용
- 정렬된 데이터 형식 및 작업 사용
- 할당 올바르게 정렬
- 가능하면 연산자 오버로드 방지
- Denormals
- 정수 부동 소수점 이중성 활용
- 템플릿 양식 선호
- Direct3D에서 DirectXMath 사용
- 관련 항목
접근자를 아끼는 용도로 사용
벡터 기반 작업은 SIMD 명령 집합을 사용하며 특수 레지스터를 사용합니다. 개별 구성 요소에 액세스하려면 SIMD 레지스터에서 스칼라 레지스터로 다시 이동해야 합니다.
가능하면 일련의 개별 벡터 접근자를 사용하는 대신 XMVECTOR 의 모든 구성 요소를 한 번에 초기화하는 것이 더 효율적입니다.
올바른 컴파일 설정 사용
Windows x86 대상의 경우 /arch:SSE2를 사용하도록 설정합니다. 모든 Windows 대상에 대해 /fp:fast를 사용하도록 설정합니다.
기본적으로 DirectXMath Library for Window x86 대상에 대한 컴파일은 정의된 _XM_SSE_INTRINSICS_ 사용하여 수행됩니다. 즉, 모든 DirectXMath 기능이 SSE2 지침을 사용합니다. 그러나 다른 코드에서도 마찬가지입니다.
DirectXMath 외부의 코드는 컴파일러 기본값을 사용하여 처리됩니다. 이 스위치가 없으면 생성된 코드에서 효율성이 낮은 x87 코드를 자주 사용할 수 있습니다.
항상 사용 가능한 최신 버전의 컴파일러를 사용하는 것이 좋습니다.
적절한 경우 Est 함수 사용
많은 함수에는 Est로 끝나는 동등한 추정 함수가 있습니다. 이러한 함수는 성능 향상을 위해 일부 정확도를 거래합니다. Est 함수는 속도를 위해 정확도를 희생할 수 있는 중요하지 않은 계산에 적합합니다. 정확도 손실과 속도 증가의 정확한 양은 플랫폼에 따라 달라집니다.
예를 들어 XMVector3AngleBetweenNormalsEst 함수는 XMVector3AngleBetweenNormals 함수 대신 사용할 수 있습니다.
정렬된 데이터 형식 및 작업 사용
SSE2를 지원하는 Windows 버전의 SIMD 명령 집합에는 일반적으로 정렬되고 정렬되지 않은 버전의 메모리 작업이 있습니다. 정렬된 작업의 사용은 더 빠르며 가능한 경우 선호되어야 합니다.
DirectXMath 라이브러리는 변형 벡터 형식, 구조 및 함수를 통해 정렬되고 정렬되지 않은 액세스 기능을 제공합니다. 이러한 변형은 이름 끝에 "A"로 표시됩니다.
예를 들어 정렬되지 않은 XMFLOAT4X4 구조체와 XMStoreFloat4 및 XMStoreFloat4A 함수에서 각각 사용되는 정렬된 XMFLOAT4X4A 구조체가 있습니다.
할당 올바르게 정렬
DirectXMath 라이브러리의 기본인 SSE 내장 함수의 정렬된 버전은 정렬되지 않은 버전보다 빠릅니다.
이러한 이유로 XMVECTOR 및 XMMATRIX 개체를 사용하는 DirectXMath 작업은 해당 개체가 16 바이트 정렬된 것으로 가정합니다. 권장 Windows( 올바른 컴파일 설정 사용) 컴파일러 설정을 사용하여 DirectXMath 라이브러리에 대해 코드를 컴파일하는 경우 스택 기반 할당에 대해 자동으로 수행됩니다. 그러나 XMVECTOR 및 XMMATRIX 개체를 포함하는 힙 할당 또는 이러한 형식 으로 캐스팅이 이러한 맞춤 요구 사항을 충족하는지 확인하는 것이 중요합니다.
64비트 Windows 메모리 할당은 16 바이트 정렬되지만 기본적으로 할당된 32비트 버전의 Windows 메모리에서 8 바이트만 정렬됩니다. 메모리 맞춤을 제어하는 방법에 대한 자세한 내용은 _aligned_malloc.
STL(표준 템플릿 라이브러리)과 정렬된 DirectXMath 형식을 사용하는 경우 16 바이트 맞춤을 보장하는 사용자 지정 할당자를 제공해야 합니다. 사용자 지정 할당자를 작성하는 예제는 Visual C++ 팀 블로그 를 참조하세요(malloc/free 대신 구현에서 _aligned_malloc 및 _aligned_free 사용하려는 경우).
참고
일부 STL 템플릿은 제공된 형식의 맞춤을 수정합니다. 예를 들어 make_shared<> 제공된 사용자 형식의 맞춤을 준수하거나 준수하지 않을 수 있는 일부 내부 추적 정보를 추가하여 정렬되지 않은 데이터 멤버를 생성합니다. 이 경우 정렬된 형식 대신 정렬되지 않은 형식을 사용해야 합니다. 많은 Windows 런타임 개체를 포함하여 기존 클래스에서 파생되는 경우 클래스 또는 구조체의 맞춤을 수정할 수도 있습니다.
가능하면 연산자 오버로드 방지
편의 기능으로 XMVECTOR 및 XMMATRIX 와 같은 다양한 형식에는 일반적인 산술 연산에 대한 연산자 오버로드가 있습니다. 이러한 연산자 오버로드는 수많은 임시 개체를 만드는 경향이 있습니다. 성능에 중요한 코드에서 이러한 연산자 오버로드를 방지하는 것이 좋습니다.
Denormals
0에 가까운 계산을 지원하기 위해 IEEE 754 부동 소수점 표준에는 점진적 언더플로에 대한 지원이 포함됩니다. 점진적 언더플로는 비정규화된 값을 사용하여 구현되며, 비정규를 처리할 때 많은 하드웨어 구현이 느립니다. 고려해야 할 최적화는 DirectXMath에서 사용하는 벡터 작업에 대해 비정규 처리를 사용하지 않도록 설정하는 것입니다.
비정규 처리 변경은 스레드 전 기준으로 _controlfp_s 루틴을 사용하여 수행되며 성능이 향상될 수 있습니다. 이 코드를 사용하여 비정규 처리를 변경합니다.
#include <float.h>;
unsigned int control_word;
_controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
참고
64비트 버전의 Windows에서는 SSE 명령이 벡터 작업뿐만 아니라 모든 계산에 사용됩니다. 비정규 처리를 변경하면 DirectXMath에서 사용하는 벡터 작업뿐만 아니라 프로그램의 모든 부동 소수점 계산에 영향을 줍니다.
정수 부동 소수점 이중성 활용
DirectXMath는 4개의 단정밀도 부동 소수점 또는 4개의 32비트(부호 있거나 서명되지 않은) 값의 벡터를 지원합니다.
DirectXMath 라이브러리를 구현하는 데 사용되는 명령 집합에는 동일한 데이터를 여러 가지 형식으로 처리하는 기능이 있기 때문입니다. 예를 들어 동일한 벡터를 부동 소수점 및 정수 데이터 특정 최적화로 처리할 수 있습니다. 정수 벡터 초기화 루틴 및 비트 단위 연산자를 사용하여 부동 소수점 값을 조작하여 이러한 최적화를 가져올 수 있습니다.
DirectXMath 라이브러리에서 사용하는 단정밀도 부동 소수점 숫자의 이진 형식은 IEEE 754 표준을 완전히 준수합니다.
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
IEEE 754 단일 정밀도 부동 소수점 숫자로 작업할 때는 일부 표현이 특별한 의미를 갖는다는 점을 명심해야 합니다(즉, 앞의 설명을 따르지 않음). 예제는 다음과 같습니다.
- 양의 0은 0입니다.
- 음수 0이 0x80000000
- Q_NAN 07FC0000입니다.
- +INF가 0x7F800000
- -INF가 0xFF800000
템플릿 양식 선호
XMVectorSwizzle, XMVectorPermute, XMVectorInsert, XMVectorShiftLeft, XMVectorRotateLeft 및 XMVectorRotateRight에 대한 템플릿 양식이 있습니다. 일반 함수 형식 대신 이러한 형식을 사용하면 컴파일러에서 훨씬 더 효과적인 구현을 만들 수 있습니다. SSE의 경우 이 값은 하나 또는 두 개의 _mm_shuffle_ps 값으로 축소되는 경우가 많습니다. ARM-NEON의 경우 XMVectorSwizzle 템플릿은 일반적인 VTBL 스위즐/퍼뮤트 대신 다양한 특수 사례를 활용할 수 있습니다.
Direct3D에서 DirectXMath 사용
DirectXMath의 일반적인 용도는 Direct3D에서 사용할 그래픽 계산을 수행하는 것입니다. Direct3D 10.x 및 Direct3D 11.x를 사용하면 DirectXMath 라이브러리를 다음과 같은 직접적인 방법으로 사용할 수 있습니다.
ColorRGBA 매개 변수에서 직접 Color 네임스페이스 상수를 사용하여 ID3D11DeviceContext::ClearRenderTargetView 또는 ID3D10Device::ClearRenderTargetView 메서드를 호출합니다. Direct3D 9의 경우 IDirect3DDevice9::Clear 메서드 호출에서 Color 매개 변수로 사용하려면 XMCOLOR 형식으로 변환해야 합니다.
XMFLOAT4/XMVECTOR 및 XMFLOAT4X4/XMMATRIX 형식을 사용하여 HLSL float4 또는 matrix/float4x4 형식에서 참조할 상수 버퍼 구조를 설정합니다.
참고
XMFLOAT4X4/XMMATRIX 형식은 행 주 형식입니다. 따라서 /Zpr 컴파일러 스위치(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR 컴파일 플래그)를 사용하거나 HLSL에서 행렬 형식을 선언할 때 row_major 키워드(keyword) 생략하는 경우 행렬을 상수 버퍼로 설정할 때 행렬을 바꿔야 합니다.
Direct3D 10.x 및 Direct3D 11.x를 사용하면 pData 멤버(D3D10_MAPPED_TEXTURE2D)에서 Map 메서드(예: ID3D11DeviceContext::Map)에서 반환된 포인터를 가정할 수 있습니다.pData, D3D10_MAPPED_TEXTURE3D. pData 또는 D3D11_MAPPED_SUBRESOURCE. pData) 는 기능 수준 10_0 이상을 사용하거나 D3D11_USAGE_STAGING 리소스를 사용할 때마다 16 바이트 정렬됩니다.