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

iPhone 5s A7 64bit CPU와 AArch64

(원문 : iPhone 5s A7 64bit CPU と AArch64)

스마트폰에 탑재되어 있는 메모리 용량은 굉장히 빠른 페이스로 증가하고 있습니다. 다음 페이지에 일본에 발매된 단말의 스펙을 모았습니다.

대충 훑어보기만 했지만 대충 이런 느낌↓이 아닐까 합니다.

2008년 128MB
2009년 128MB〜256MB
2010년 256MB〜512MB
2011년 512MB〜1GB
2012년 1GB〜2GB
2013년 1/2GB〜?

특히 Android 기기에서 용량증가가 두드러짐을 알 수 있습니다. 이 페이스가 앞으로도 지속될 거라고 예상하면, 내년에는 32bit 프로세서의 벽에 부딪히게 됩니다.

많은 RAM 용량을 필요로 하게 되는 원인 중 하나로 화면의 고해상도화를 들 수 있겠습니다. 이쪽도 RAM 용량에 지지 않을 페이스로 진화해왔습니다.

2008년 128MB           480x320              x1.0
2009년 128MB〜256MB    480x320〜800x480     x2.5
2010년 256MB〜512MB    854x480〜1024x768    x5.12
2011년 512MB〜1GB      854x480〜1280x800    x6.67
2012년 1GB〜2GB        854x480〜2560x1600   x26.67
2013년 1/2GB〜?       1280x720〜?

고해상도화에 따라 응용 프로그램에 필요한 묘화 리소스량도 증가합니다. 해상도가 높으면 CPU 묘화가 늦어지므로, GPU의 지원이 필수가 됩니다. 묘화나 레이어의 합성 등 OS가 관리하는 GPU 리소스도 대폭으로 늘어나게 됨을 예상할 수 있습니다.

그 이외에도 여러가지 요인이 있을거라 생각하지만, 프로세서 전체의 성능향상과 그에 맞춘 요구에서 볼때, 64bit화는 자연스러운 흐름이라 할 수 있을 것입니다.

하지만 지금 가장 RAM 용량이 절박한 것은 Android 쪽입니다. iOS는 Android의 약 절반 정도의 RAM 용량으로 동작하고 있으므로, iPhone 5s의 A7가 스타트를 끊은 것은 상당히 의외라는 생각이었습니다.

64bit화의 메리트로 주소 공간의 확장을 듭니다만, 그 외에도 여러가지 메리트가 있습니다. 특히 64bit mode는 호환성의 족쇄에서 벗어날 큰 기회이며, 64bit 화되면서 여러가지 아키텍처의 변경이 이루어지고 있는 듯 합니다.

하나는 명령어 집합이나 레지스터 등 하드웨어적인 아키텍처의 변경이고, 또 하나는 소프트웨어적인 결정사항을 재설계할 수 있다는 것입니다. 전혀 쓰이지않지만 호환성 때문에 남겨져있는 기능이라던가, 설계가 낡아서 영 좋지않게 된 사양등을 쳐낼 수 있게 됩니다. (물론 32bit 동작 mode에서는 호환성이 유지됩니다.)

ARM은 로드 스토어형의 RISC 프로세서이지만, 한 인스트럭션에 복수의 기능이 들어간 다기능적인 명령체계였습니다. 예를 들면 명령 필드에 Condition Code가 포함되어 있어 조건부 실행이 가능하거나, 소스 오퍼랜드에 Shifter가 들어가 있는 등 상당히 독특합니다.

AArch64에서는 전혀 다른 명령어 집합이 되었습니다. 보다 심플하고 실용적인 설계가 되었다고들 합니다만, 대충 본 결과 편리해보이는 특이한 기능도 풍부하여, 충분히 ARM 답다고 느꼈습니다.

컴파일러의 출력 코드와 비교하면, 함수에 있어서는 64bit 쪽이 명령수가 줄어 컴팩트해짐을 알 수 있습니다.

위에서 적은 바와 같이 ARMv7에서는 호환성 문제로 softfp (soft-float)가 사용되는 경우가 있습니다. 부동소수점값도 함수 입출력에서는 일단 정수 레지스터를 경유하게 되어 낭비가 발생합니다.

AArch64 (64bit)에서는 이런 배려가 필요없으므로 처음부터 hard-float에 해당되게 된 것 같습니다.

// AArch64
__Z5func3fff:                           ; @_Z5func3fff
; BB#0:
	fadd	s0, s0, s1
	fsub	s0, s0, s2
	ret	lr

__Z5func419__simd128_float32_tS_:       ; @_Z5func419__simd128_float32_tS_
; BB#0:
	fmul.4s	v1, v0, v1
	fadd.4s	v0, v1, v0
	ret	lr
// AArch32
__Z5func3fff:                           @ @_Z5func3fff
@ BB#0:
	vmov	d18, r1, r1
	vmov	d20, r0, r0
	vmov	d16, r2, r2
	vadd.f32	d18, d20, d18
	vsub.f32	d0, d18, d16
	vmov	r0, s0
	bx	lr

__Z5func419__simd128_float32_tS_:       @ @_Z5func419__simd128_float32_tS_
@ BB#0:
	vmov	d17, r2, r3
	vmov	d16, r0, r1
	mov	r0, sp
	vld1.32	{d18, d19}, [r0]
	vmul.f32	q9, q8, q9
	vadd.f32	q8, q9, q8
	vmov	r0, r1, d16
	vmov	r2, r3, d17
	bx	lr

64bit 화가 직접적인 이유인 건 아니지만, ABI나 스택 프레임을 개량할 수 있다는 것도 실제 퍼포먼스에 영향을 주는게 아닐까 합니다.

실제로 Windows의 x86/x64에서도, 양쪽을 다 써보면 같은 CPU 위에서도 64bit 쪽이 확실히 빠름을 알 수 있습니다. 64bit 성능이 떨어진다는 Core 2에서도 확실히 효과가 납니다.

x64에서 레지스터 수가 두배로 늘어난 것이 가장 큰 원인이겠지만, ABI처럼 소프트웨어 디자인면에서 호환성을 가질 필요가 없다는 점도 커다란 메리트가 됨을 예상할 수 있습니다.

iPhone의 메모리 공간에는 아직 여유가 있습니다만, 퍼포먼스의 향상이나 이용효율을 올려 전력절감으로 유도한다는 의미에서도 iPhone 5s의 64bit 화는 의미가 있다고 생각합니다.

어제 ARMv8 AArch64의 부동소수점 연산속도 비교를 위해 컴파일러의 출력 코드를 조사해본 결과, 그때는 이것↓이 뭔지 몰랐습니다.

	orr.16b	v5, v1, v1

의미없는 or 명령은 레지스터간의 move였습니다. (mov v5,v1)

관련글

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

iPhone 5s A7 CPU의 부동소수점 연산속도(2) (AArch64/64bit)

(원문 : iPhone 5s A7 CPU の浮動小数点演算速度 (2) (AArch64/64bit))

64bit mode (AArch64)에서 테스트해봤습니다. 명령도 레지스터 구조도 다르므로 다른 코드를 썼습니다. 검증이 불완전하기에 이 결과에 잘못된 부분이 들어가 있을 가능성이 있습니다.

                  (1)    (2)     (3)       (4)       (5)
               iPhone5  HTL21  Nexus10   iPhone5s iPhone5s
                Swift   Krait Cortex-A15  AArch32  AArch64
                  A6   APQ8064 Exynos5D     A7       A7
                1.3GHz  1.5GHz  1.7GHz    1.3GHz?  1.3GHz?
--------------------------------------------------------------------
a:m44 vmla_A Q   1.293   1.337   0.619     0.700    -----
b:m44 vmla_B Q   1.359   0.931   0.569     0.670    -----
c:m44 vmla_A D   1.669   1.889   0.557     0.649    -----
d:m44 vmla_B D   1.329   1.532   0.568     0.745    -----
A:m44 vfma_A Q   1.632   1.882   0.746     0.707    0.692  (fmla v)
B:m44 vfma_B Q   1.594   0.695   0.840     0.699    0.696  (fmla v)
e:fadds      A   3.090   2.774   2.383     3.551    1.043  (fadd s)
f:fmuls      A   3.167   2.747   2.369     3.475    1.548  (fmul s)
g:fmacs      A   6.180   5.574   2.956     3.480    -----
h:vfma.f32   A   6.180   2.747   2.957     3.480    3.185  (fmadd s)
i:vadd.f32 D A   3.091   2.762   1.183     1.031    1.031  (fadd.2s)
j:vmul.f32 D A   3.168   2.746   1.478     1.545    1.545  (fmul.2s)
k:vmla.f32 D A   3.166   5.604   1.480     1.567    -----
o:vfma.f32 D A   3.167   2.833   1.479     1.574    1.753  (fmla.2s)
l:vadd.f32 Q A   3.090   2.801   2.365     1.031    1.039  (fadd.4s)
m:vmul.f32 Q A   3.166   2.761   2.364     1.548    1.548  (fmul.4s)
n:vmla.f32 Q A   3.167   5.606   2.367     1.574    -----
*:vfma.f32 Q A   -----   -----   -----     -----    1.696  (fmla.4s)
p:fadds      B   6.181   3.467   2.956     6.953    3.663  (fadd s)
q:fmuls      B   6.180   3.556   3.558     6.652    3.296  (fmul s)
r:fmacs      B   2.361   6.298   5.912     9.867    -----
s:vfma.f32   B   2.363   3.430   5.910     9.859    3.292  (fmadd s)
t:vadd.f32 D B   3.090   3.529   2.958     3.663    3.643  (fadd.2s)
u:vmul.f32 D B   3.169   3.447   2.364     3.114    3.289  (fmul.2s)
v:vmla.f32 D B   6.180   6.293   4.728     6.185    -----
z:vfma.f32 D B   6.181   3.437   4.730     6.188    6.237  (fmla.2s)
w:vadd.f32 Q B   3.090   3.457   2.961     3.659    3.641  (fadd.4s)
x:vmul.f32 Q B   3.167   3.428   2.363     3.101    3.276  (fmul.4s)
y:vmla.f32 Q B   6.179   6.372   4.729     6.199    -----
*:vfma.f32 Q B   -----   -----   -----     -----    6.226  (fmla.4s)

↑수치는 실행시간(초) 수치가 작을수록 고속

scalar 연산은 예상대로 AArch64 쪽이 고속으로 실행되는 것 같습니다. AArch64에서는 vector 때와 동등하여 NEON에 통합되었다고 예상됩니다.

ARMv8의 AArch64에서는 SIMD 레지스터의 구조가 변하여, 전부 128bit 사이즈가 되었습니다. 스칼라 연산은 그 일부만을 이용하는 구조로, x86의 SSE와 정확하게 같은 방식입니다. 스칼라를 로드할 때에도 레지스터 전체가 클리어됩니다.

32bit (ARMv7)에서는 Q(128bit) x 8 = D(64bit) x 16 = S(32bit) x 32가 같은 영역이었습니다. D는 S의 2개분이고, Q에는 S레지스터가 4개 포함되어 있습니다.

AArch32의 경우, 스칼라 연산은 레지스터의 일부 다시 쓰기에 해당되기에 그 때문에 파이프라인 실행효율이 떨어지는 것이라 예상됩니다.

fmadd가 느린 경향은 Swift와 같습니다. AArch64에서는 이 명령만 4 오퍼랜드였습니다.

A: 와 B: 는 다음과 같습니다.

; A: m44 fmla  A Q
ldp q0, q1, [%0]
ldp q2, q3, [%0,#32]
ldp q4, q5, [%1]
ldp q6, q7, [%1,#32]

fmul.4s	v8, v0, v4[0]
fmla.4s	v8, v1, v4[1]
fmla.4s	v8, v2, v4[2]
fmla.4s	v8, v3, v4[3]
str  q8, [%2]
〜
fmul.4s	v8, v0, v7[0]
fmla.4s	v8, v1, v7[1]
fmla.4s	v8, v2, v7[2]
fmla.4s	v8, v3, v7[3]
str  q8, [%2,#48]
; B: m44 fmla  B Q
ldp q0, q1, [%0]
ldp q4, q5, [%1]
ldp q6, q7, [%1,#32]

fmul.4s	v8,  v0, v4[0]
fmul.4s	v9,  v0, v5[0]
fmul.4s	v10, v0, v6[0]
fmul.4s	v11, v0, v7[0]
ldp	q2, q3, [%0,#32]
〜
fmla.4s	v8,  v3, v4[3]
fmla.4s	v9,  v3, v5[3]
fmla.4s	v10, v3, v6[3]
fmla.4s	v11, v3, v7[3]
stp  q8,  q9,  [%2]
stp  q10, q11, [%2,#32]

레지스터 번호가 일치하므로 굉장히 쓰기 쉬워졌습니다.

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

iPhone 5s의 Apple A7 GPU

(원문 : iPhone 5s の Apple A7 GPU)

A7의 GPU는 「Apple A7 GPU」라고 표시되며 독자적인 이름이 붙어있습니다.

GL_VERSION: OpenGL ES 3.0 Apple A7 GPU - 27.10
GL_RENDERER: Apple A7 GPU
GL_VENDOR: Apple Inc.
GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 3.00

PVRTC에 대응하므로 PowerVR 계열일 가능성이 높습니다. 하지만 PVRTC(v2)가 없고 범용성이 높은 ETC2/EAC로 바뀌기도 해서 PowerVR에 의존하는 방침전환이 엿보이는 것 같습니다.

Mali-T604, Adreno 320과의 비교입니다. (참고)

                                      Nexus 7 (2013)  Nexus 10  iPhone 5s
                                        Adreno 320   Mali-T604   A7 GPU
-------------------------------------------------------------------------
=== GL3:texture
GL_MAX_3D_TEXTURE_SIZE                      1024       4096       2048
GL_MAX_TEXTURE_SIZE                         4096       4096       4096
GL_MAX_ARRAY_TEXTURE_LAYERS                 256        4096       2048
GL_MAX_TEXTURE_LOD_BIAS                     15.984     255.996    16.000
GL_MAX_CUBE_MAP_TEXTURE_SIZE                4096       4096       4096
GL_MAX_RENDERBUFFER_SIZE                    4096       4096       4096
GL_MAX_DRAW_BUFFERS                         4          4          4
GL_MAX_COLOR_ATTACHMENTS                    4          4          4
GL_MAX_VIEWPORT_DIMS                        4096       4096       4096
=== GL3:elements
GL_MAX_ELEMENTS_INDICES                     -1         16777216   150000
GL_MAX_ELEMENTS_VERTICES                    -1         16777216   1048575
=== GL3:vertex
GL_MAX_VERTEX_ATTRIBS                       16         16         16
GL_MAX_VERTEX_OUTPUT_COMPONENTS             69         64         64
=== GL3:pixel
GL_MAX_FRAGMENT_INPUT_COMPONENTS            71         60         64
=== GL3:program
GL_MIN_PROGRAM_TEXEL_OFFSET                 -8         -8         -8
GL_MAX_PROGRAM_TEXEL_OFFSET                 7          7          7
GL_MAX_VARYING_COMPONENTS                   64         60         60
GL_MAX_VARYING_VECTORS                      16         15         15
=== GL3:output stream
GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 64    64         64
GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS       4     4          4
GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS    4     4          4
GL_MAX_SAMPLES                                   4     4          8
=== GL3:uniform block
GL_MAX_VERTEX_UNIFORM_COMPONENTS            1024       1024       2048
GL_MAX_VERTEX_UNIFORM_VECTORS               256        256        512
GL_MAX_VERTEX_UNIFORM_BLOCKS                12         12         12
GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS   --         50176      51200
GL_MAX_FRAGMENT_UNIFORM_COMPONENTS          896        4096       896
GL_MAX_FRAGMENT_UNIFORM_VECTORS             224        1024       224
GL_MAX_FRAGMENT_UNIFORM_BLOCKS              12         12         12
GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 197504     53248      50048
GL_MAX_UNIFORM_BUFFER_BINDINGS              24         36         24
GL_MAX_UNIFORM_BLOCK_SIZE                   65536      16384      16384
GL_MAX_COMBINED_UNIFORM_BLOCKS              24         24         24
=== GL3:tex
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS           16         16         16
GL_MAX_TEXTURE_IMAGE_UNITS                  16         16         16
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS         32         32         32

지금까지와는 다른 GPU라는 것을 알 수 있습니다.

Uniform Block 수는 다른 것과 마찬가지로 12입니다. Fragment의 Uniform 수는 Adreno와 마찬가지로 OpenGL ES 3.0의 최소치인 896(224)으로 Vertex 쪽이 높게 설정되어 있습니다. PowerVR 5는 다른 GPU와 비교해도 Uniform 수가 적어, 한번에 전송할 수 있는 데이터 량에 제한이 있었습니다. OpenGL ES 3.0의 A7에서는 이 부분이 해소되어 오히려 여유가 있습니다.

다만 OpenGL ES 2.0 Context에서의 호환성을 위해서인지 종래의 PowerVR SGX 5 계와 같은 값이 리턴되는 듯 합니다.

GL_VERSION: OpenGL ES 2.0 Apple A7 GPU - 27.10
GL_RENDERER: Apple A7 GPU
GL_VENDOR: Apple Inc.
GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 1.00

Precision:
 0: [15 15] 10
 1: [15 15] 10
 2: [127 127] 23
 3: [15 14] 0
 4: [15 14] 0
 5: [31 30] 0
 6: [15 15] 10
 7: [15 15] 10
 8: [127 127] 23
 9: [15 14] 0
10: [15 14] 0
11: [31 30] 0

=== GL2:texture
GL_MAX_TEXTURE_SIZE                      4096
GL_MAX_CUBE_MAP_TEXTURE_SIZE             4096
GL_MAX_VIEWPORT_DIMS                     4096
=== GL2:vertex
GL_MAX_VERTEX_ATTRIBS                    16
GL_MAX_VERTEX_UNIFORM_VECTORS            128
GL_MAX_VARYING_VECTORS                   8
=== GL2:pixel
GL_MAX_FRAGMENT_UNIFORM_VECTORS          64
GL_MAX_RENDERBUFFER_SIZE                 4096
=== GL2:tex
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS        8
GL_MAX_TEXTURE_IMAGE_UNITS               8
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS      8

TextureFormat 4
00=8c00  GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
01=8c01  GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
02=8c02  GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
03=8c03  GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG

Android 4.3 + OpenGL ES 3.0의 경우에는 사실상 2.0와 3.0으로 Context 차이가 없었지만, 이점에 있어서도 iOS다운 사양이 되어있습니다. 예를 들면 Android 4.2의 Mali-T604은 Fragment Uniform수가 256(vec4)였지만, 4.3에서는 OpenGL ES 2.0에서도 3.0과 마찬가지로 1024(vec4)를 리턴합니다.

OpenGL ES 2.0 Context에서는 Vertex Texture Unit이 유효하게 되어있다는 점이 마음에 걸립니다. A7만 그런건가 싶었지만 PowerVR SGX 5XT에서도 같은 값이 되어있으므로 iOS 7에서 추가된 것일지도 모르겠습니다.

위 글에도 적혀있습니다만 glGetShaderPrecisionFormat()의 결과에 차이가 보입니다. float lowp가 mediump와 같은 fp16이고, int highp도 32bit가 되어있습니다. 아래 페이지도 갱신했습니다.

다만 위 페이제도 적혀있듯 API로 얻을 수 있는 사양과 실제 연산결과가 다른 경우가 있습니다. 같은 fix10이라도 PowerVR series 5(SGX535/540) & Tegra2/3와 series 5XT(SGX543MP/554MP)는 셰이딩 결과에 차이가 있습니다. 5XT 쪽이 Fragment 부분만 lowp의 정밀도가 높아져있는 것으로 보입니다.

A7 GPU의 경우에는 처음부터 fp16이므로, 호환성 측면에서도 잘 맞춰진 사양이라 생각합니다.

관련 글

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

iOS7과 iPhone 5s의 sRGB 대응과 텍스처 포맷

(원문 : iOS7 と iPhone 5s の sRGB 対応とテクスチャフォーマット)

iPhone 5s가 발매되어 OpenGL ES 3.0 대응 단말이 늘어났습니다. OpenGL ES 3.0에 대응하는 입수가능 단말로서는 3종류째의 GPU입니다.

  • Nexus 10 ( Android 4.3 + Mali-T604 )
  • Nexus 7(2013)/Nexus 4 ( Android 4.3 + Adreno 320 )
  • iPhone 5s ( iOS 7 + Apple A7 GPU )

Nexus 10용으로 작성된 OpenGL ES 3.0의 묘화 코드도 iPhone 5s에서 쉽게 동작했습니다. 역시 Adreno 320에서는 아직 문제가 좀 남아있는 것 같습니다.

sRGB

OpenGL ES 3.0를 이용할 수 있는 것은 Apple A7를 탑재한 iPhone 5s 뿐이지만, iOS 7.0로 갱신함으로써 종래 단말에서도 기능확장이 이루어진 듯 합니다. 그 하나가 지난회 기사에서 이야기한 sRGB 대응입니다.

iPhone 5s의 OpenGL ES 3.0에서 sRGB를 다룰수 있게 된 것은 당연하지만, iPad 4나 iPhone 5 등 PowerVR SGX554MP/543MP에서도 extension으로 동등한 상호변환이 지원되게 되었습니다. (아래 페이지도 갱신)

예를 들면 PVRTC에서도 GL_EXT_pvrtc_sRGB에 의해 sRGB에서 리니어로 변환할 수 있게 되어 있습니다.

  • GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT
  • GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT
  • GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT
  • GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT

지난번의 표↓를 갱신했습니다.

          OpenGL ES 3.0 での sRGB 対応
-----------------------------------------
ETC1         가능(ETC2)
ETC2         가능
PVRTC  (v1)  가능         (PowerVR 만)
PVRTC2 (v2)  가능         (PowerVR 만)
ATITC        불가         (Adreno 만)
ASTC         가능
S3TC(DXT1)   가능

iOS에서 대응하는 포맷은 PVRTC (v1)뿐으로 PVRTC2 (v2)는 포함되지 않는 것 같습니다. 또 프레임버퍼에 대해 리니어에서의 변환 GL_EXT_sRGB)도 지원하고 있습니다.

iOS는 원래 Renderbuffer를 직접 만들었으므로, EGL/WGL같은 기능선택은 불필요합니다. 또한 GLK (GLKit)이라면 한줄 바꾸는 것 만으로 대응되므로, Android에서 고생하던 것이 거짓말처럼 간단하게 처리되었습니다.

PowerVR SGX535 (iPhone4)는 미확인이지만, SGX543MP/554MP에서는 iOS 7.0 에서 Apple A7 GPU와 마찬가지로 동작하고 있음이 확인되었습니다.

텍스처 포맷

iOS에서도 OpenGL ES 3.0에서는 Android와 마찬가지로 ETC2/EAC를 이용할 수 있게 되었습니다. Android 등 다른 환경과 호환성을 유지하기 쉽게 되었습니다.

                           ETC1  ETC2/EAC  DXT(S3TC)  PVRTC(v1)  ATITC
----------------------------------------------------------------------
iOS PowerVR        ES 2.0   --     --        --        ◎         --
iOS PowerVR?       ES 3.0   ◎     ◎        --        ◎         --
Android PowerVR    ES 2.0   ◎     --        --        ◎         --
Android Tegra2/3/4 ES 2.0   ◎     --        ◎        --         --
Android Adreno200  ES 2.0   ◎     --        --        --         ◎
Android Adreno300  ES 3.0   ◎     ◎        --        --         ◎
Android Mali400    ES 2.0   ◎     --        --        --         --
Android Mali600    ES 3.0   ◎     ◎        --        --         --

Android의 모든 단말과 iOS ES 3.0 이후는 ETC1의 읽기가 가능합니다.

Android/iOS 구별없이 현 상황의 모든 OpenGL ES 3.0 디바이스에서 ETC2/EAC를 사용할 수 있습니다.

관련글

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

iPhone 5s A7 CPU의 부동소수점 연산속도 (32bit)

(원문 : iPhone 5s A7 CPU の浮動小数点演算速度 (32bit))

iPhone 5s의 부동소수점 연산속도를 명령단위로 비교해보았습니다. A7의 CPU core는 ARMv8으로 64bit 명령에 대응하지만, 여기서는 AArch32 (32bit mode)의 VFP/NEON 명령을 비교해보겠습니다. 64bit mode (AArch64)에서는 레지스터의 개수와 view가 다르므로 결과가 달라질 가능성이 있습니다.

                 (1)      (2)    (3)     (4)      (5)      (6)
                Nexus7  EVO 3D  iPhone5  HTL21  Nexus10  iPhone5s
              Cortex-A9 Scorpion Swift   Krait Cortex-A15   ?
                Tegra3  MSM8660    A6  APQ8064 Exynos5D     A7
                1.2GHz  1.2GHz  1.3GHz  1.5GHz  1.7GHz    1.3GHz?
-----------------------------------------------------------------
a:m44 vmla_A Q   3.959   2.859   1.293   1.337   0.619     0.700
b:m44 vmla_B Q   2.002   1.136   1.359   0.931   0.569     0.670
c:m44 vmla_A D   3.980   3.053   1.669   1.889   0.557     0.649
d:m44 vmla_B D   2.003   1.434   1.329   1.532   0.568     0.745
A:m44 vfma_A Q   -----   -----   1.632   1.882   0.746     0.707
B:m44 vfma_B Q   -----   -----   1.594   0.695   0.840     0.699
e:fadds      A   3.343   3.383   3.090   2.774   2.383     3.551
f:fmuls      A   3.337   3.383   3.167   2.747   2.369     3.475
g:fmacs      A   3.337   3.379   6.180   5.574   2.956     3.480
h:vfma.f32   A   -----   -----   6.180   2.747   2.957     3.480
i:vadd.f32 D A   3.426   3.377   3.091   2.762   1.183     1.031
j:vmul.f32 D A   3.421   3.383   3.168   2.746   1.478     1.545
k:vmla.f32 D A   3.792   3.380   3.166   5.604   1.480     1.567
l:vadd.f32 Q A   6.688   3.377   3.090   2.801   2.365     1.031
m:vmul.f32 Q A   6.681   3.384   3.166   2.761   2.364     1.548
n:vmla.f32 Q A   6.681   3.380   3.167   5.606   2.367     1.574
o:vfma.f32 D A   -----   -----   3.167   2.833   1.479     1.574
p:fadds      B   3.347   5.917   6.181   3.467   2.956     6.953
q:fmuls      B   4.195   5.917   6.180   3.556   3.558     6.652
r:fmacs      B   6.688   8.451  12.361   6.298   5.912     9.867
s:vfma.f32   B   -----   -----  12.363   3.430   5.910     9.859
t:vadd.f32 D B   3.421   5.916   3.090   3.529   2.958     3.663
u:vmul.f32 D B   3.422   5.073   3.169   3.447   2.364     3.114
v:vmla.f32 D B   7.561   8.451   6.180   6.293   4.728     6.185
w:vadd.f32 Q B   6.705   5.916   3.090   3.457   2.961     3.659
x:vmul.f32 Q B   6.683   5.074   3.167   3.428   2.363     3.101
y:vmla.f32 Q B   7.532   8.457   6.179   6.372   4.729     6.199
z:vfma.f32 D B   -----   -----   6.181   3.437   4.730     6.188

↑수치는 실행시간(초) 수치가 작을수록 고속

빠르다고 생각한 iPhone 5 A6의 Swift로부터 1년, A7은 더욱 강력한 연산능력을 갖고 있는 듯 합니다. 거의 동 클럭(?)에서도 Swift의 최대 3배의 스루풋을 내며, 클럭차가 있음에도 Cortex-A15에 필적하는 점수가 나오고 있습니다.

특히 NEON 명령이 고속이라는 걸 알 수 있습니다. D와 Q에서 차가 없으므로, 연산은 128bit 단위라고 예상할 수 있습니다. 그럼에도 Cortex-A15의 64bit 2pipe로 실현된 속도를 따라잡고 있으므로, 어디까지나 억측이지만 A7은 128bit pipe가 복수 존재하고 있을 가능성이 있습니다.

반면, VFP 쪽은 다른 CPU와 차이가 거의 없는 듯, 동작 클럭분만큼 차가 나고 있습니다. 다만 Swift에서 극단적으로 느렸던 스칼라의 덧곱셈[각주:1]명령에 있어서는 A7에서 제대로 결점을 극복했다는 것을 알 수 있습니다. 그래도 레이턴시는 Swift 정도는 아니지만 비교적 큰 편입니다.

ARMv8의 아키텍처 변경에 따라, NEON 명령에서도 배정밀도 연산이 지원되게 되었습니다. 이 테스트는 단정밀도의 32bit 부동소수점 연산이지만, 만약 배정밀도로 비교한다면 32bit ARMv7세대와는 차이가 훨씬 벌어지게 될겁니다.

x86에서도 SSE2가 배정밀도 연산을 지원하게 됨으로써, 호환성 목적 이외로는 FPU (x87)을 사용할 필요가 없어지게 되었습니다. 실제로 Windows x64의 64bit mode에서는 FPU를 사용하지 않고 SSE 명령만이 이용되고 있습니다.

마찬가지로 ARMv8도 Advanced NEON이 배정밀도를 커버함으로써 VFP를 나눌 필요가 없어지게 되었습니다. AArch32에서는 VFP 명령이었던 것이 AArch64에서는 NEON의 스칼라로 바뀌었음을 예상할 수 있습니다.

Krait, Swift, Cortex-A15과 ARMv7-A로 VFPv4세대의 CPU가 겨우 갖춰졌다 싶었더니, 그에 더해 새로운 세대의 CPU가 등장해버렸습니다. 진짜 퍼포먼스는 AArch64 (64bit mode)에서 발휘되므로, 지금부터가 진짜라 할 수 있겠습니다.

a:〜z: 각개의 상세와 설명은 과거의 기사를 참조해십시오. Cortex-A8을 포함한 여러 기종의 결과를 아래 페이지에 정리했습니다.

  1. 積和의 의역. 값을 곱하고 난 후 목표값에 더하는 명령. vmla, vfla등. [본문으로]

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

Nexus 10 CPU Cortex-A15의 속도

(원문 : Nexus 10 CPU Cortex-A15 の速度)

지난회에는 부동소수점에 대해서만 다뤘습니다만, Cortex-A15로 다른 테스트도 해봤습니다.

지난회의 부동소수점 연산에서는 Cortex-A15가 가장 좋은 결과를 냈습니다. 코어 단독의 피크 성능은 Swift/Krait와 동일하지만, 64비트 2파이프 덕분에 연산효율이 높게 나왔다는 인상이었습니다.

                                  time(sec)  MB/sec  MBPS/GHz
-------------------------------------------------------------
Exynos 5D  Cortex-A15 1.7GHz  x2   1.49      72.61    42.71
A6X        Swift      1.4GHz? x2   1.75      61.82    44.16?
APQ8064    Krait      1.5GHz  x4   2.28      47.64    31.82

싱글 스레드 코어 1개에서의 비교입니다.

이번 테스트에는 NEON이나 부동소수점이 포함되어 있지 않습니다. 이 경우 동일 클럭에서의 실행 성능은 대체로 Swift과 비슷한 듯 합니다. A6X보다 Exynos 5 Dual 쪽이 동작클럭이 높은만큼, 리스트 안에서는 Nexus 10이 가장 좋은 성적을 냈습니다.

Krait는 유일한 4코어라 절대적인 속도는 빼어나지만 단독으로는 그다지 성능이 나오지 않았습니다. 부동소수점 연산 성능은 좋았지만, 이쪽 테스트에서는 다른 CPU와 차이가 벌어지는 형태가 되었습니다.

머지않아 Tegra4/Exynos 5 Octa 등 Cortex-A15의 쿼드코어가 나오므로 시스템 전체의 퍼포먼스는 상당히 좋은 성적을 낼 듯 합니다. Atom으로는 비교가 되지 않으므로, Core i는 둘째치더라도 다른 CPU와 비교하고 싶어지는 기분을 알 것 같습니다.

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

Nexus 10 CPU Cortex-A15의 부동소수점 연산속도

(원문 : 3DMark Android 版の結果から)

Nexus10을 입수하여 ARMv7A의 새로운 CPU core 3종류가 갖춰졌기에 Apple Swift, Qualcomm Krait, ARM Cortex-A15를 비교해보겠습니다. 동작 클럭이 가장 높다는 것도 있지만, Cortex-A15의 동작은 Swift보다도 고속이었습니다.

                (1)     (2)     (3)     (4)     (5)     (6)     (7)
               iPad3   Nexus7  EVO 3D iPhone5  iPad4   HTL21  Nexus10
                A5X    Tegra3 MSM8660   A6      A6X   APQ8064 Exynos5D
               ARM A9  ARM A9 Scorpion Swift   Swift   Krait  ARM A15
               1.0GHz  1.2GHz  1.2GHz  1.3GHz? 1.4GHz? 1.5GHz  1.7GHz
               VFPv3   VFPv3   VFPv3   VFPv4   VFPv4   VFPv4   VFPv4
----------------------------------------------------------------------
a:m44 vmla_AQ  4.784   3.959   2.859   1.293   1.204   1.337   0.619
b:m44 vmla_BQ  2.408   2.002   1.136   1.359   1.266   0.931   0.569
c:m44 vmla_AD  4.781   3.980   3.053   1.669   1.554   1.889   0.557
d:m44 vmla_BD  2.406   2.003   1.434   1.329   1.238   1.532   0.568
A:m44 vfma_AQ  -----   -----   -----   1.632   1.519   1.882   0.746
B:m44 vfma_BQ  -----   -----   -----   1.594   1.484   0.695   0.840
e:fadds     A  4.010   3.343   3.383   3.090   2.878   2.774   2.383
f:fmuls     A  4.010   3.337   3.383   3.167   2.953   2.747   2.369
g:fmacs     A  4.012   3.337   3.379   6.180   5.757   5.574   2.956
h:vfma.f32  A  -----   -----   -----   6.180   5.756   2.747   2.957
i:vadd.f32 DA  4.111   3.426   3.377   3.091   2.877   2.762   1.183
j:vmul.f32 DA  4.110   3.421   3.383   3.168   2.950   2.746   1.478
k:vmla.f32 DA  4.512   3.792   3.380   3.166   2.951   5.604   1.480
l:vadd.f32 QA  8.023   6.688   3.377   3.090   2.878   2.801   2.365
m:vmul.f32 QA  8.022   6.681   3.384   3.166   2.952   2.761   2.364
n:vmla.f32 QA  8.025   6.681   3.380   3.167   2.950   5.606   2.367
o:vfma.f32 DA  -----   -----   -----   3.167   2.494   2.833   1.479
p:fadds     B  4.014   3.347   5.917   6.181   5.756   3.467   2.956
q:fmuls     B  5.013   4.195   5.917   6.180   5.756   3.556   3.558
r:fmacs     B  8.023   6.688   8.451  12.361  11.514   6.298   5.912
s:vfma.f32  B  -----   -----   -----  12.363  11.513   3.430   5.910
t:vadd.f32 DB  4.113   3.421   5.916   3.090   2.881   3.529   2.958
u:vmul.f32 DB  4.118   3.422   5.073   3.169   2.949   3.447   2.364
v:vmla.f32 DB  9.027   7.561   8.451   6.180   5.755   6.293   4.728
w:vadd.f32 QB  8.021   6.705   5.916   3.090   2.879   3.457   2.961
x:vmul.f32 QB  8.029   6.683   5.074   3.167   2.950   3.428   2.363
y:vmla.f32 QB  9.026   7.532   8.457   6.179   5.759   6.372   4.729
z:vfma.f32 DB  -----   -----   -----   6.181   5.755   3.437   4.730
----------------------------------------------------------------------
↑수치는 실행시간(초) 수치가 작을 수록 빠름

(1)=Apple iPad 3          A5X      Cortex-A9  x2 1.0GHz  VFPv3 i6.1
(2)=ASUS Nexus 7          Tegra 3  Cortex-A9  x4 1.2GHz  VFPv3 A4.2
(3)=HTC EVO 3D ISW12HT    MSM8660  Scorpion   x2 1.2GHz  VFPv3 A4.0
(4)=Apple iPhone 5        A6       Swift      x2 1.3GHz? VFPv4 i6.1
(5)=Apple iPad 4          A6X      Swift      x2 1.4GHz? VFPv4 i6.1
(6)=HTC J butterfly HTL21 APQ8064  Krait      x4 1.5GHz  VFPv4 A4.1
(7)=Samsung Nexus 10      Exynos5D Cortex-A15 x2 1.7GHz  VFPv4 A4.2

테스트 항목에 대한 자세한 내용은 아래를 참조(a:~z:)

iPad4/EVO 3D/Butterfly는 다시 측정해서 예전보다 수치가 올라가있습니다.

a:~d: 를 보면, 1.7GHz의 Cortex-A15는 Swift의 2배 가까운 수치입니다. 명령 단독으로도 효율이 올라가, Krait와 비교해도 64bit D(float2) 명령의 속도차는 클럭의 차이 이상입니다.

64bit D(float2)와 128bit Q(float4)에 차이가 있는 것을 보면, 아마도 Cortex-A15은 64bit 단위의 ALU가 2 파이프 존재하고 있는게 아닐까 합니다. 128bit Q(float4)의 속도는 Swift/Krait와 큰 차이가 없으므로 연산능력의 피크 속도 자체는 Swift/Krait와 동일한 듯 합니다. D, Q의 차가 없는 Scorpion/Swift/Krait는 128bit 단위라 생각할 수 있습니다.

(1)~(3) Cortex-A9/Scorpion의 a:~d:에서는 AQ/AD와 BQ/BD의 결과에 큰 차이가 납니다. 이것이 CPU 세대간의 차이로, (4)~(7)의 Swift/Krait/Cortex-A15에서는 명령순에 의존하지 않고 일정한 효율로 실행되고 있음을 알 수 있습니다.

이전에도 적었던 대로 Swift는 스칼라의 덧곱셈[각주:1] 명령만 느립니다. NEON의 벡터에서는 덧곱셈이라도 딱히 속도가 떨어지진 않으므로, 무언가 구조적인 이유에 의한 것이라 생각됩니다.

마찬가지로 Krait에도 귀찮은 패턴이 있습니다. ARM에서는 VFPv4 이후 FMA(Fused Multiply add) 명령이 추가되었습니다. Krait는 vfma(FMA)보다도 종래의 vmla 명령이 2배 가까이 느립니다. 반올림처리할 vmul[각주:2] + vadd[각주:3]로 전개될 가능성이 있습니다.

Krait 최적화

a:~d: 의 연산은 vmla[각주:4]를 사용하지만, Krait에서는 이 명령이 느립니다. vfma[각주:5]로 바꿈으로서 고속화할 가능성이 있기에 시험해봤습니다.

// A: mat44 neon_AQ의 vfma화

   vmul.f32  q8, q0, d8[0]
   vlma.f32  q8, q1, d8[1]
   vlma.f32  q8, q2, d9[0]
   vlma.f32  q8, q3, d9[1]
    :
↓
   vmul.f32  q8, q0, d8[0]
   vdup.f32  q9,  d8[1]
   vfma.f32  q8, q1, q9
   vdup.f32  q10, d9[0]
   vfma.f32  q8, q2, q10
   vdup.f32  q11, d9[1]
   vfma.f32  q8, q3, q11
    :


// B: mat44 neon_AQ의 vfma화

   vmul.f32  q8,  q0, d8[0]
   vmul.f32  q9,  q0, d10[0]
   vmul.f32  q10, q0, d12[0]
   vmul.f32  q11, q0, d14[0]
   vmla.f32  q8,  q1, d8[1]
   vmla.f32  q9,  q1, d10[1]
   vmla.f32  q10, q1, d12[1]
   vmla.f32  q11, q1, d14[1]
    :
↓
   vmul.f32  q8,  q0, d8[0]
   vmul.f32  q9,  q0, d10[0]
   vmul.f32  q10, q0, d12[0]
   vmul.f32  q11, q0, d14[0]
   vdup.32   q12, d8[1]
   vdup.32   q13, d10[1]
   vdup.32   q14, d12[1]
   vdup.32   q15, d14[1]
   vfma.f32  q8,  q1, q12
   vfma.f32  q9,  q1, q13
   vfma.f32  q10, q1, q14
   vfma.f32  q11, q1, q15
    :

vfma는 vmla와 달리 vector * scalar가 안되므로 그냥 바꾸는 것만으로는 동작하지 않습니다. SSE와 마찬가지로 데이터 복사가 필요하므로 vdup[각주:6]를 삽입했습니다.

               ARM A9  ARM A9 Scorpion Swift   Swift   Krait  ARM A15
----------------------------------------------------------------------
a:m44 vmla_AQ  4.784   3.959   2.859   1.293   1.204   1.337   0.619
b:m44 vmla_BQ  2.408   2.002   1.136   1.359   1.266   0.931   0.569
    ↓
A:m44 vfma_AQ  -----   -----   -----   1.632   1.519   1.882   0.746
B:m44 vfma_BQ  -----   -----   -----   1.594   1.484   0.695   0.840

A: 는 상당히 느리지만 B: 는 효과가 있었습니다. 이 케이스에서는 Krait가 Cortex-A15을 넘어섰습니다.

예상대로 Swift, Cortex-A15에서는 역효과로, vdup가 늘어난 만큼 느려졌습니다.

참고로 vmla과 vfma는 반올림 타이밍이 다르므로 엄밀하게 말하자면 결과가 일치하지 않습니다. vfma 쪽은 오차가 적지만, C의 코드에서 보통으로 쓰면 fmacs[각주:7]가 되므로 검증코드에서 멋지게 assert에 걸렸습니다.

  1. 積和의 의역. 값을 곱하고 난 후 목표값에 더하는 명령. vmla, vfla등. [본문으로]
  2. 스칼라 부동소수점 곱셈 [본문으로]
  3. 스칼라 부동소수점 덧셈 [본문으로]
  4. 스칼라 부동소수점의 덧곱셈. 각주 1을 참고 [본문으로]
  5. vmla와 마찬가지로 스칼라 부동소수점의 덧곱셈 명령이지만 목표값에 더하기 전에 반올림하지 않음 [본문으로]
  6. 벡터 레지스터의 각 요소를 스칼라 값으로 채우는 명령 [본문으로]
  7. 구버전의 단정밀도 스칼라 덧곱셈 명령 [본문으로]

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

3DMark Android 판의 결과로부터

(원문 : 3DMark Android 版の結果から)

Android판 3DMark 앱의 DEVICE CHANNEL에서 각 기종의 결과를 볼 수 있습니다. 매우 흥미진진하고, 보고 있으면 재미있는 데이터이기에 정리해봤습니다.

SoC      CPU       core  GPU              Score        CPU vs GPU
-----------------------------------------------------------------
APQ8064  Krait      x4   Adreno 320       8000-11000   CPU <= GPU*
Exynos5D Cortex-A15 x2   Mali-T604        7800        *CPU >  GPU
MSM8960  Krait      x2   Adreno 225       5000-6500    CPU <= GPU*
MSM8x60  Scorpion   x2   Adreno 220       3700-5000    CPU <= GPU*
Tegra3   Cortex-A9  x4   ULP GeForce(12)  3000-4000   *CPU >> GPU
K3V2     Cortex-A9  x4   Vivante GC4000   3400-3700   *CPU >> GPU
OMAP4470 Cortex-A9  x2   PowerVR SGX544   3600        *CPU >> GPU
Exynos4Q Cortex-A9  x4   Mali-400MP4      2500-3400   *CPU >> GPU
Z2460    Atom       x1   PowerVR SGX540   2400        *CPU >> GPU
Exynos4D Cortex-A9  x2   Mali-400MP4      1600-2100   *CPU >> GPU
OMAP44x0 Cortex-A9  x2   PowerVR SGX540   1300-3400   *CPU >> GPU
MSM8x55  Scorpion   x1   Adreno 205       1750         CPU <  GPU*
RK3066   Cortex-A9  x2   Mali-400MP4      1200-2800   *CPU >> GPU
Tegra2   Cortex-A9  x2   ULP GeForce(8)   1400-2100   *CPU >> GPU

・Score 값이 높을수록 빠름
・수치는 항상 변동하므로 현시점에서의 참고치로 봐주시길.

가장 오른쪽 열은 CPU와 GPU 중에 어느 쪽의 수치가 더 높은지를 나타냅니다.

전체적으로는 Adreno22x/320의 수치가 높은 경향이 있습니다. 오른쪽 열을 보면 알 수 있듯, CPU 보다도 GPU의 점수가 높은 것은 Qualcomm (Adreno)의 프로세서뿐입니다.

Exynos/OMAP/Tegra 등, Quallcom 이외에는 모두 CPU 쪽이 높게 나타나고 있고, 그 차이도 2배 정도까지 넓혀져 있습니다.

어째서 이런 결과가 되었는지 생각해보겠습니다.

CPU

CPU는 두 그룹으로 나뉘어집니다.

(A) Cortex-A9, Scorpion
(B) Cortex-A15, Krait

(B)는 새로운 세대의 CPU 코어로, 동작 클럭 차이도 있지만 실행효율 자체도 향상되어 있습니다. 예를 들어 (A)가 2 명령 디코드(역자 주: 원문에는 deocde라고 되어있으나 decode의 오타라고 생각되어 수정)의 Out-of-Order 실행인 것에 대해, (B)그룹은 3 명령으로 끌어올려져 있습니다. 동일 클럭, 동 코어수라도 Krait, Cortex-A15 쪽이 고속입니다.

Adreno

각 회사의 SoC/GPU는 다종다양하며 특기분야가 확실합니다. Adreno는 ATI 의 흐름을 이은 모바일용 GPU로, 가장 데스크탑용 GPU에 가까운 기능을 갖고 있습니다. 이것은 다른 GPU에는 없는 커다란 특징입니다.

예를 들자면 정점 텍스처나 볼륨 텍스처(3D 텍스처) 등, 모바일 용도로는 별로 필요치 않은 기능에도 확실히 대응하고 있습니다. 다음 링크에 실제로 각종 GPU 기능을 비교한 표가 있습니다.

프래그먼트 셰이더(픽셀 셰이더)의 연산정밀도도 fp32의 highp 고정으로, 묘화 품질 역시 데스크탑 GPU와 동등합니다. 퍼포먼스를 높이기 위해 눈에 보이는 것을 희생할 필요가 업습니다.

그 대신 초기의 Adreno 20x/AMD Z430에서는 정점 캐시가 없었고, 데스크탑 GPU와 동등한 묘화기능을 가진 반면, 퍼포먼스는 생각했던 것만큼 나오지 않는 경향이 있었습니다. 이 점은 Adreno 22x 이후 개량되어, 묘화 프리미티브에 의존하지 않으며 스루풋이 크게 올라가 있습니다.

복잡한 셰이더도 상당히 잘 돌아가지만, 애플리케이션에 따라서는 그다지 속도가 나오지 않는 것도 있습니다. 어디까지나 상상에 지나지 않지만, Adreno는 OpenGL ES 1.1의 고정 파이프를 시뮬레이션하는 부분이 그다지 좋지 않은 것일지도 모릅니다. (미확인입니다)

셰이더를 사용하여 묘화할 경우, Adreno는 극단적으로 모바일에 특화된 최적화할 필요가 없으며, 셰이더를 그대로 이식해도 속도가 잘 떨어지지 않는 경향이 있습니다. 이 점이 벤치마크에서 유리하게 작용하는 것이 아닐까 합니다. 정리하자면,

  • highp 고정이라 연산정밀도를 떨어트리지 않아도 속도가 변하지 않음
  • 모바일용으로 mediump/lowp화하는 등 특별한 최적화를 할 필요가 없음
  • PC의 묘화 품질에서 떨어트릴 필요가 없음
  • Uniform 수, Sampler 수도 많고 Extension도 풍부하여 호환성을 유지하기 쉬움
  • 통합 셰이더이므로, 정점 부하, 픽셀 부하 어느쪽에든 대응하기 쉬움

또 Adreno 320는 OpenGL ES 3.0에 대응하는 새로운 설계의 GPU 코어이므로, 세대적으로도 상당한 고성능입니다. 사용되는 API 가 ES 2.0이므로, 아직 잠들어있는 하드웨어 기능도 있습니다. 앞으로도 더욱 점수가 늘어날 것이라고 생각됩니다.

Mali-400MP4

GPU의「코어 수」는 GPU에 따라 세는 방법이 다르며 단위도 제각각입니다. 단말의 스펙에 GPU의 코어 수가 적혀있는 경우도 있지만, 성능의 지표가 될 수 있는 건 어디까지나 동일 GPU끼리 비교했을 때 뿐입니다.

PowerVR SGX의 MP1~4은 CPU와 거의 같은 개념으로, GPU 그 자체가 복수 존재하여 병렬로 동작합니다.

Tegra의 코어 수는 GPU 내의 연산 유닛 수를 나타냅니다. G80 이후의 데스크탑 GPU에 맞춘 것으로, 통합 셰이더의 스트림 프로세서에 해당하는 것이 몇개분인지를 나타냅니다. Discrete 이지만 정점, 프래그먼트 둘다 카운트됩니다.

Mali-400은 다음 페이지의 그림(Mali-400 MP Image)에 나와있듯 프래그먼트 프로세서의 유닛 수를 선택할 수 있으며, MP1~MP4라고 불립니다. 이 숫자에는 정점 프로세서가 포함되어 있지 않습니다.

Tegra2/3에서도 8→12로 코어 수는 늘어났지만 정점 유닛 수는 동일합니다. 만약 Mali-400MP와 마찬가지로 프래그먼트 프로세서만을 센다면 Tegra2의 ULP GeForce(8)는 정점 4 + 프래그먼트 4로 MP1, Tegra3의 ULP GeForce(12)는 Vertex 4 + Fragment 8로 MP2가 될 것입니다.

다시 말해 Discrete Shader의 GPU에서는 스펙 표기상의 코어 수가 늘어나도, 정점 성능이 향상된다고는 할 수 없습니다.

Galaxy S2에서 Mali-400MP4가 등장했을 때에는 픽셀 퍼포먼스가 굉장히 높아, 다른 GPU와 비교해도 좋은 성능이었습니다. 하지만 그 후 복잡한 3D 장면에서는 정점 성능이 병목이 되었다는 것을 알고 계실겁니다.

위에서 보신 대로 MP4에서도 정점 성능은 늘어나지 않았고, 10~20만 정도의 비교적 낮은 레벨에서 한계에 부딪히고 있는 듯 합니다.

3DMark Ice Storm의 폴리곤 수는 상당한 하이폴리곤인 듯 한데, Mali-400MP4의 퍼포먼스가 나타나지 못하는 것은 그 때문이라고 생각됩니다.

픽셀 셰이더는 mediump이라 엄밀히는 데스크탑 GPU보다 연산정밀도가 떨어집니다. 다만 Tegra나 PowerVR SGX처럼 최적화를 위해 정밀도를 깎아야할 정도로 빡빡하지는 않습니다. 정점이 병목일 뿐 픽셀측은 mediump 고정이므로 그다지 손을 댈 필요는 없을 듯 합니다.

Mali-T604 이후는 통합 셰이더이므로 특성이 또 달라질 것입니다.

Tegra2/3

Mali-400MP와 같은 Discrete Shader지만, 특성은 정반대입니다. 정점에 여유가 있는 대신에 픽셀이 부족해져서, 비교적 하이폴리곤에 심플한 머티리얼일 때 퍼포먼스가 좋아지는 듯 합니다.

Mali-400MP와 마찬가지로 픽셀 정밀도는 mediump까지이지만, 복잡한 셰이더 코드에서는 lowp를 병용하여 질보다 속도를 우선해야할 경우가 생깁니다. 깊이의 해상도도 다른 GPU보다 떨어집니다.

다른 GPU보다도 대응 확장기능이 떨어지며, 하드웨어 기능도 대담하게 삭제되었습니다. 예를 들자면 깊이 텍스처를 사용할 수 없어 섀도우 맵을 컬러 맵에 써넣어야 합니다. 깊이를 압축해야하기에, 셰이더에도 추가 연산 코드가 필요합니다. OpenGL ES 2.0의 사양 상 깊이 텍스처 대응이 필수는 아니지만, 대응하지 않는 GPU는 Tegra2/3 뿐입니다.

3DMark에서는 비교적 하이폴리곤이지만 Mali-400MP 정도로 점수가 떨어지지는 않으며, GPU의 능력으로서 타당한 결과라 생각됩니다.

NVIDIA답지 않은 성능의 GPU도 아마도 이것이 마지막이 아닐까 합니다. Tegra4에서는 기능면에서도 속도면에서도 크게 손을 대어 점수가 상당히 늘어날 것이라 생각됩니다.

PowerVR SGX

이전의 기사에서도 적었듯, PowerVR SGX 5xx는 2종류가 있습니다. Android 단말에서는 낡은 Series 5(SGX540)가 많아, GPU의 성능면에서 벤치마크의 점수가 그다지 좋지 않은 듯합니다. 그 외에도 생각할 수 있는 원인이 있습니다.

PowerVR SGX는 어떤 묘화든 낭비없이 해내는 경향이 있습니다. 정점이 많은 장면이든 픽셀이 많은 장면이든 유연하게 따라갑니다.

사용 방법의 자유도도 높아 화질 우선으로 써도 되고, 속도 중시도 할 수 있고, 용도에 따라 마음대로 쓸 수 있습니다. 그 반면, 정해진 해법이 없이 상황에 맞는 판단이 요구됩니다.

예를 들자면 Uniform 수는 퍼포먼스를 생각한다면 128개 이내, 이식성이나 사용성을 위해서는 256개를 사용한다던가 하는 것입니다. (과거 기사의 comment를 참조)

또 픽셀에 highp fp32를 쓸 수 있어, 데스크탑 GPU와 동일한 정밀도로 묘화할 수 있습니다. 이 경우 퍼포먼스가 떨어지므로, 속도를 생각한다면 겉보기를 희생해서 mediump, lowp로 바꿀 수 있습니다.

다른 GPU와 달리 TBDR(타일 기반 지연 렌더링)이므로, ALU의 이용효율이 전체 퍼포먼스에 주는 영향이 큽니다.

통상의 GPU는 래스터라이저에서 픽셀 셰이더(프래그먼트 셰이더)가 호출되므로, 파이프라인 대기 사이클이 존재합니다. 래스터라이저나 깊이 테스트 등, 다른 스테이지가 막혀있을 때는 셰이더를 줄여도 속도가 크게 변화하지 않습니다.

PowerVR SGX는 지연 렌더링이므로, 픽셀 셰이더가 호출될 때에는 래스터라이저 등 다른 스테이지가 완료되어 있는 상태입니다. 셰이더의 명령을 줄이면 줄일수록 직접 퍼포먼스에 영향을 주므로 최적화가 힘들어지기 쉽습니다.

여기가 가장 Adreno와 다른 포인트로, 퍼포먼스를 우선한다면 상당히 손을 많이 써야할 필요가 있습니다. 고속화를 할 여지가 남아있다고도 할 수 있겠습니다.

첨언하자면 품질이 변할 경우 벤치마크 비교로는 올바르다 할 수 없기에, 3DMark는 비교적 높은 연산정밀도로 렌더링하고 있지 않나 생각됩니다. 만약 그렇다면 Tegra/Mali와는 달리 PowerVR의 점수는 더욱 오를 여지가 남아있게 됩니다.

iOS 판이 나오면, 어느 정도나 PowerVR SGX에 최적화되었는지 알 수 있게 될 것입니다.

결론

  • 아마도 각 GPU 별 셰이더 최적화가 그다지 강하지 않으므로, 속도가 잘 떨어지지 않는 Adreno가 유리
  • OpenGL ES 3.0 대응 최신 GPU + 신 CPU와, 한발 앞서 세대교체한 Qualcomm (Krait quad + Adreno 320)가 역시 빠름

+ Recent posts