2013-05-10 2 views
3

저는 14 살 때부터 게임 엔진 북을 읽었습니다. (그 당시 나는 물건을 이해하지 못했습니다 : P) 이제 꽤 오랜 세월이 흘러서 제 게임 엔진의 수학적 기초를 프로그래밍하기 시작했습니다. 나는이 '도서관'을 어떻게 디자인 할 것인지 오랫동안 생각 해왔다. (필자가 "정리 된 파일 세트"라고 말함) 몇 년에 한 번씩 새로운 SIMD 명령어 세트가 나왔고, 나는 그들에게 낭비하지 않기를 바랬다. (이것에 대해 잘못 생각하면 말해.)함수 포인터를 사용하여 게임 엔진 수학 라이브러리에서 SIMD 사용하기 ~ 좋습니다.

나는 적어도 다음과 같은 특성을 가지고 싶어 :

  • 그것을 경우 SIMD를 런타임시 SIMD를 가지고 있는지 확인하고 사용하는 것이 가능 만들기를 그렇지 않은 경우에는 정상적인 C++ 버전을 사용합니다. (약간의 호출 오버 헤드가있을 수 있습니까?)
  • 컴파일 타임에 이미 타겟을 알고 있으면 SIMD 또는 일반 C++ 용으로 컴파일 할 수있게 만듭니다. 컴파일러는 SIMD 또는 C++가 사용되는지 여부를 알기 때문에 호출을 인라인으로 만들거나 교차 최적화에 적합하게 만들 수 있습니다.

편집 - 나는 소스 코드 휴대용 만들고 싶어 너무 너무

그래서 나는 함수 포인터를 사용하는 것이 좋은 해결책이 될 것이라고 생각이 다른 deviced 다음 86 (-64)에서 실행할 수있는 I 프로그램을 시작할 때 정적으로 초기화합니다. 그리고 적합한 기능 (예 : Matrix/Vector의 곱셈)이 호출됩니다.

이 디자인의 장점과 단점 (어느 쪽이 더 중량이 더 큽니까?)은 무엇이라고 생각합니까? 위에서 설명한대로 두 속성을 모두 사용하여 만들 수 있습니까? 기독교

+0

[컴파일러 내장 함수] (http://en.wikipedia.org/wiki/Intrinsic_function) 함수를 살펴볼 수 있습니다. SIMD 명령어에 직접 매핑되는 명령어가 많이 있습니다. 타겟 플랫폼이 해당 명령어를 지원하지 않으면 컴파일러는 현재 명령어를 에뮬레이트 할만큼 똑똑해야합니다. g.e. [여기 VS2012 내장 함수] (http://msdn.microsoft.com/en-us/library/26td21ds%28v=vs.110%29.aspx). –

+0

SSE2 지침은 최소 10 년 동안 사용할 수 있습니다. 구형 컴퓨터에서 실행되는 게임에 관심이 있습니까? (예 : 휴대 전화로 게임을하거나 그런 식으로 게임을하는 것은 아닙니다.) –

+0

@MatsPetersson 나는 나의 질문을 편집했다! 나는 그것이 모든 시스템에 이식되어야한다는 것을 추가하는 매우 중요한 목표를 잊었다. –

답변

4

그것은 당신이 호출 할 수있는 루틴에 대한 결정을 내릴 수있는 권리 세분화하는 것이 중요합니다. 너무 낮은 수준에서 이렇게하면 함수 디스패치 오버 헤드가 문제가됩니다. 약간의 명령어가있는 작은 루틴은 단지 인라인 된 것보다 일종의 함수 포인터 디스패치 메커니즘을 통해 호출되는 경우 매우 비효율적이 될 수 있습니다. 아키텍처 관련 루틴은 합리적인 양의 데이터를 처리해야 함수 파견 비용을 무시할 수있을 정도로 커지지 않고 지원되는 각 아키텍처에 대해 아키텍처 비 특정 코드를 추가로 컴파일해야하기 때문에 코드가 크게 늘어나는 것이 이상적입니다.

+0

수학 라이브러리의 대부분의 함수는 크기가 작기 때문에 런타임에 SIMD가 있는지를 추론하고 사용 가능한 경우이를 사용할 수 있는지 속성을 삭제하도록 제안 하시겠습니까? SIMD를 상위 레벨로 사용하는 결정을 내리셨습니까? 나는 그것이 더 효율적일 것이라고 확신하지만 코드가 그렇게 부 풀릴 수밖에 없다. –

+0

일반적으로 SIMD의 실질적인 이점을 얻으려면 각 루틴이 합리적으로 큰 데이터 세트에서 작동해야합니다. 즉, 두 개의 SIMD 벡터를 추가하는 것이 아니라 두 개의 1D 또는 2D 어레이를 추가하는 것입니다. 그렇게하면 루틴 자체에서 효율성이 높아지며 함수 디스패치 오버 헤드가 중요하지 않습니다. 인텔이이를 어떻게 처리하는지 살펴보십시오. 그것의 IPP 라이브러리. –

+0

Intels 사이트에서 IPP 라이브러리를 찾을 수 있지만 라이브러리의 내부 링크가있을 수 있습니까? 내 수학 라이브러리를 어떻게 디자인하라고 제안 했습니까? –

0

가장 간단한 방법은 게임을 두 번 컴파일하는 것입니다. 한 번만 SIMD를 사용하도록 설정하고 한 번만 사용하면됩니다. _may_i_use_cpu_feature 검사를 수행하는 작은 실행기 응용 프로그램을 만든 다음 올바른 빌드를 실행합니다.

함수 포인터를 통해 행렬 곱하기를 호출하여 발생하는 이중 간접 참조는 좋지 않습니다. 사소한 수학 함수를 인라이닝하지 않고 상점 전체에 함수 호출을 도입 할 것이고, 이러한 호출은 많은 레지스터를 저장/복원해야 할 것입니다 (왜냐하면 포인터 뒤에있는 코드는 런타임까지 알 수 없기 때문입니다) .

이 시점에서 이중 간접 참조가없는 최적화되지 않은 버전은 함수 포인터를 사용하여 SSE 버전보다 훨씬 뛰어난 성능을 보입니다.

여러 플랫폼을 지원하는 경우 쉽고 간단 할 수도 있습니다. ARM 네온은 SSE4와 유사하기 때문에 일부 매크로 뒤의 intruction을 래핑 할 가치가 있지만 네온 또한 충분히 괴롭습니다.

#if CPU_IS_INTEL 

#include <immintrin.h> 
typedef __m128 f128; 

#define add4f _mm_add_ps 

#else 

#include <neon.h> 
typedef float32x4 f128; 

#define add4f vqadd_f32 

#endif 

인텔 말에 시작하고, 나중에 팔 이식에 가장 큰 문제는 좋은 일들이 많이 존재하지 않는다는 것입니다. ARM에서 셔플 링이 가능하지만 이는 또한 귀찮은 일입니다. 부문 내적 및 SQRT이 같은 SIMD에 대해 생각하는 경우

을 (당신이 당신의 자신의 뉴턴의 반복을 수행해야합니다에만 상호 추정) ARM에 존재하지 않습니다

struct Vec4 
{ 
    float x; 
    float y; 
    float z; 
    float w; 
}; 

그러면 은 semi-ok 래퍼 뒤에 SSE와 NEON을 래핑 할 수 있습니다. AVX512와 AVX2에 관해서, 당신은 아마 망설여 질 것이다.

그러나 당신이 구조의 배열 형식을 사용하여 SIMD에 대해 생각하는 경우 :

struct Vec4SOA 
{ 
    float x[BIG_NUM]; 
    float y[BIG_NUM]; 
    float z[BIG_NUM]; 
    float w[BIG_NUM]; 
}; 

그럼 당신은 AVX2/AVX512의 버전을 생성 할 수 있습니다 기회가있다. 그러나 이와 같은 조직의 코드로 작업하는 것은 세계에서 가장 쉬운 방법은 아닙니다.