※ 이 글은 오가사와라 히로유키(小笠原博之) 씨가 블로그에 적은 글을 번역한 것입니다. 사정에 따라 예고없이 삭제될 수 있으므로 양해부탁드립니다.

OpenGL ES 2.0 Tegra2/3/4의 Fragment Shader와 동적루프

(원문 : OpenGL ES 2.0 Tegra2/3/4 の Fragment Shader と動的ループ)

Desktop GPU에서 Vertex Shader와 Pixel Shader의 사양이 완전히 통일된 것은 Direct3D 10의 ShaderModel 4.0 이후입니다. 그때까지는 쓸 수 있는 명령이나 Constant 영역, 레지스터 수, 프로그램 사이즈, 텍스처 명령등 여러가지 차이가 남아있었습니다.

Hardware의 Unified Shader화는 ATI의 Xbox360 GPU가 먼저 시작하였습니다. 이것이 지금의 Qualcomm Adreno로 이어집니다. 그 후 일반적인 Desktop PC용으로도 NVIDIA GeForce 8800 (G80)이 등장하여, 이후 Unified Shader Model이 당연해지게 됩니다.

OpenGL ES 2.0의 Shader 세대는 Direct3D 9의 Shader Model 3.0에 해당합니다만, 많은 Mobile GPU가 이미 Unified Shader화되어있습니다. 그렇기에 딱히 Vertex와 Fragment Shader의 성능차를 의식할 필요는 없었습니다.

그 중, Tegra2/3/4는 G70 베이스의 GPU로, Unified Shader화되기 전의 제한이 남아있는 드문 케이스입니다.

코멘트에서 Tegra의 Fragment Shader는 동적 루프를 쓸 수 없다는 지적을 받았기에 테스트해보았습니다.

// (1) 동적 루프
int loop= int( uniform_value );
for( int i= 0 ; i < loop ; i++ ){
   ...
}

↑루프 회수를 동적으로 구하는 경우, Vertex Shader는 통과하지만 Fragment Shader에서는 컴파일 시에 에러가 발생합니다.

예전에 적었듯 Uniform 배열의 index 접근↓(2)도 Tegra의 Fragment Shader에서는 에러가 뜹니다. 둘 다 Direct3D 9 세대의 제한이라 생각됩니다.

// (2) Uniform 배열
uniform vec4 src_color[30];
~
int index= int(tex_color.x);
vec4 color= src_color[ index ]; // Tegra의 Fragment Shader에서는 Error

Tegra 4에서도 마찬가지이므로, 기능은 대폭 확장되었지만 GPU의 베이스는 같다는 것을 알 수 있습니다. 참고로 Tegra와 같은 Discrete Type의 Shader Unit을 갖춘 Mali-400MP에서는 작동합니다.

	     Vertex Shader            Fragment Shader
	     동적Loop  Uniform배열    동적Loop  Uniform배열
-----------------------------------------------------------
Unified      ◯         ◯              ◯         ◯
Mali-400MP   ◯         ◯              ◯         ◯
Tegra2/3/4   ◯         ◯              ERROR     ERROR

하지만 Tegra에서도 동적 분기는 가능하기에, 실행시에 루프 횟수가 변동하는 경우에도 동등한 처리를 실현할 수는 있습니다.

// (3) Tegra용 동적분기에 의한 루프
for( int i= 0 ; i< 100 ; i++ ){
    if( i >= Loop ){
        break;
    }
    ~ 동적 루프에 해당하는 부분
}

이하 정리 (모두 Fragment Shader의 경우)

컴파일 시에 루프 횟수가 정해져 있지 않으면 에러.

// (4) 루프횟수 미정  -- Tegra에서 ERROR
for( int i= start ; i< end ; i++ ){
    ~
}

루프 범위가 정해저 있으면 컴파일 가능

// (5) 상한이 정해져있는 경우 -- Tegra에서도 OK
for( int i= 0 ; i< 100 ; i++ ){
    if( i >= start && i < end ){
        ~ 동적 루프에 해당하는 부분
    }
}

아마도 아래와 같이 전개되지 않을까 생각됩니다.

i= 0;
if( i >= start && i < end ){
    ~
}
i= 1;
if( i >= start && i < end ){
    ~
}

~

i= 99;
if( i >= start && i < end ){
    ~
}

Tegra K1 이후는 ShaderModel 5.0 세대의 GPU core가 되므로 이런 하드웨어적 제한은 없어질 것입니다.

관련글

+ Recent posts