2013/09/28
iPhone 5s A7 CPU の速度比較 arm64 (ARMv8 AArch64)
下記 CPU ベンチ の結果を更新しました。
この結果だけを見れば iPhone 5 (A6) より約 1.8倍速く、
iPhone 5s は Core2 duo の 1.74GHz 相当となっています。
・CPU ベンチ
以下抜粋 (詳細は上記ページを参照してください)
前回のテストと異なり浮動小数点演算を含んでいません。
それでもやはり 32bit (AArch32) よりも 64bit (AArch64) の方が速くなっており、
公称値である "A6 の 2倍" に近い結果が得られました。
クロック差があるにも関わらず Core2 時代の PC と比較できる域に達しており、
少々信じられませんが clock あたりの実行効率は Core i クラスとなっています。
ただしリンク先にも書いていますが、結果にはコンパイラの性能差や実行環境の
違いも含まれている点に注意してください。
x86/x64 は VC より clang の方が高いスコアになっているので、
実際にはもう少し差が広がるものと考えられます。
またこのスコアはベンチマーク用のものです。
ARMv8 には x86/x64 と同じように AES 専用命令が搭載されていますので、
実用レベルではもっと桁違いに高速に実行できます。
ARMv8 の AES 命令を使った場合のベンチマークスコアはまだ計測できておりません。
余裕があればもう少し幅広くテストしてみたいと思います。
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・Nexus 10 CPU Cortex-A15 の速度
・Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・iPad 4/iPad mini A6X/A5 の CPU/GPU 速度
・iPhone 5 / A6 の CPU 速度 その 3
・benchmark 関連
・CPU benchmark
この結果だけを見れば iPhone 5 (A6) より約 1.8倍速く、
iPhone 5s は Core2 duo の 1.74GHz 相当となっています。
・CPU ベンチ
以下抜粋 (詳細は上記ページを参照してください)
CPU arch GHz time MB/sec 1GHzあたり -------------------------------------------------------------- Apple A7 CPU ARMv8 (arm64) 1.3 1.04s 104.27MB/s 80.21MB Apple A7 CPU ARMv8 (armv7s) 1.3 1.16s 93.04MB/s 71.57MB Cortex-A15 ARMv7A 1.7 1.49s 72.61MB/s 42.71MB A6 swift ARMv7A(armv7s) 1.3 1.87s 57.96MB/s 44.58MB Krait ARMv7A 1.5 2.28s 47.64MB/s 31.82MB A5 Cortex-A9 ARMv7A(armv7) 0.8 5.78s 18.76MB/s 23.44MB Core i7 3930K x64 (Win+VC) 3.2 0.48s 228.05MB/s 71.26MB Core i7 3930K x86 (Win+VC) 3.2 0.50s 216.50MB/s 67.66MB Core2 duo x64 x64 (Win+VC) 2.4 0.75s 143.56MB/s 59.81MB Core2 duo x86 x86 (Win+VC) 2.4 0.85s 127.99MB/s 53.33MB Atom N270 x86 (Win+VC) 1.6 4.21s 25.74MB/s 16.09MB ・「MB/sec」が大きいほうが高速 ・「1GHzあたり」は同一 CPU クロックでの比較
前回のテストと異なり浮動小数点演算を含んでいません。
それでもやはり 32bit (AArch32) よりも 64bit (AArch64) の方が速くなっており、
公称値である "A6 の 2倍" に近い結果が得られました。
クロック差があるにも関わらず Core2 時代の PC と比較できる域に達しており、
少々信じられませんが clock あたりの実行効率は Core i クラスとなっています。
ただしリンク先にも書いていますが、結果にはコンパイラの性能差や実行環境の
違いも含まれている点に注意してください。
x86/x64 は VC より clang の方が高いスコアになっているので、
実際にはもう少し差が広がるものと考えられます。
またこのスコアはベンチマーク用のものです。
ARMv8 には x86/x64 と同じように AES 専用命令が搭載されていますので、
実用レベルではもっと桁違いに高速に実行できます。
ARMv8 の AES 命令を使った場合のベンチマークスコアはまだ計測できておりません。
余裕があればもう少し幅広くテストしてみたいと思います。
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・Nexus 10 CPU Cortex-A15 の速度
・Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・iPad 4/iPad mini A6X/A5 の CPU/GPU 速度
・iPhone 5 / A6 の CPU 速度 その 3
・benchmark 関連
・CPU benchmark
2013/09/27
Mac OS X で OpenGL の描画 (Xcode5/retina)
OpenGL の描画までの手順は、サンプル GL3_Text と下記のページを
参考にさせていただきました。
・white wheelsのメモ: Cocoaサンプル - OpenGLで描画
・Mac Developer Library: GL3 Text
Xcode 上で UI とオブジェクトの対応付けを行っていくスタイルのようです。
GLK はありますが GLKView はなく NSOpenGLView が用いられています。
Xcode 5 で OS X 用のプロジェクト "Cocoa Application" を作成。
MainMenu.xib を選択して、GL3_Text を真似てシーンを作ってみます。
Window → View の下に Custom View をぶら下げます。
名称をとりあえず "GLView" に変更。

右サイドの Custom Class にも "GLView" と書き込んでおきます。

プロジェクトには OpenGL.framework を追加しておきます。
GLView.h を作成。
続いて GLView.mm を作成。
Buffer Object の作成や Shader のコンパイルは (2) で行います。
(4) が実際の描画です。 glClear() 〜 glDrawElements() など。
(3) は Window のリサイズに合わせて Viewport を再設定し、
必要に応じて Projection Matrix 等を作り直します。
Retina Display に対応するには (1) の
[self setWantsBestResolutionOpenGLSurface:YES]
を追加します。
この場合 OpenGL からは 4 倍の解像度に見えることになります。
resize 時もサイズ調整が必要で、(1.1) の
[self convertRectToBacking:brect] が変換を行っています。
同じように Mouse Event 等の座標を GL 座標に合わせるには
[self convertPointToBacking:pos] を使います。
当初 Window の Resize に GLView が追従してきませんでした。
設定を比べた結果、Use Autolayout を外すと View の Autosizing を
設定できるようになりました。

↓

wgl/egl のような初期設定がなく NSOpenGLView は非常に簡単でした。
ただし initWithFrame の Profile 指定にあるように OS X 10.8
では OpenGL 3.2 までしか対応していないようです。
NSOpenGLProfileVersion3_2Core は NSOpenGL.h で定義されています。
10.9 から OpenGL 4 対応になるらしいので、GL4 の新しい
機能を使うには OS のサポートを待つ必要があります。
以前 Nexus 7 (Ubuntu) で動かしていたプログラム↓も移植できました。

参考にさせていただきました。
・white wheelsのメモ: Cocoaサンプル - OpenGLで描画
・Mac Developer Library: GL3 Text
Xcode 上で UI とオブジェクトの対応付けを行っていくスタイルのようです。
GLK はありますが GLKView はなく NSOpenGLView が用いられています。
Xcode 5 で OS X 用のプロジェクト "Cocoa Application" を作成。
MainMenu.xib を選択して、GL3_Text を真似てシーンを作ってみます。
Window → View の下に Custom View をぶら下げます。
名称をとりあえず "GLView" に変更。

右サイドの Custom Class にも "GLView" と書き込んでおきます。

プロジェクトには OpenGL.framework を追加しておきます。
GLView.h を作成。
// GLView.h #import <Cocoa/Cocoa.h> @interface GLView : NSOpenGLView @end
続いて GLView.mm を作成。
// GLView.mm #import "GLView.h" @interface GLView() { NSTimer* mpTimer; } - (id)initWithFrame:(NSRect)frameRect; - (void)reshape; - (void)render; @end @implementation GLView - (id)initWithFrame:(NSRect)frameRect { mpTimer= NULL; static const NSOpenGLPixelFormatAttribute attr[]= { NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADepthSize, 24, NSOpenGLPFAStencilSize, 8, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 0 }; NSOpenGLPixelFormat* format= [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; self= [super initWithFrame:frameRect pixelFormat:format]; if( self ){ // (1) Retina 対応 [self setWantsBestResolutionOpenGLSurface:YES]; mpTimer= [NSTimer timerWithTimeInterval:1.0/60.0 target:self selector:@selector(render) userInfo:self repeats:true]; if( mpTimer ){ [[NSRunLoop currentRunLoop] addTimer:mpTimer forMode:NSRunLoopCommonModes]; } } format= nil; return self; } - (void)prepareOpenGL { [super prepareOpenGL]; GLint vsync= GL_TRUE; [[self openGLContext] setValues:&vsync forParameter:NSOpenGLCPSwapInterval]; [[self openGLContext] makeCurrentContext]; // 〜 (2) OpenGL 初期化 } - (void)update { [super update]; } - (void)reshape { [super reshape]; NSRect brect= [self bounds]; // (1.1) Retina 対応 NSRect rrect= [self convertRectToBacking:brect]; float width= rrect.size.width; float height= rrect.size.height; // 〜 (3) screen サイズ設定など } - (void)drawRect:(NSRect)rect { } - (void)render { [[self openGLContext] makeCurrentContext]; // 〜 (4) OpenGL の描画 [[self openGLContext] flushBuffer]; } - (BOOL)isOpaque { return YES; }
Buffer Object の作成や Shader のコンパイルは (2) で行います。
(4) が実際の描画です。 glClear() 〜 glDrawElements() など。
(3) は Window のリサイズに合わせて Viewport を再設定し、
必要に応じて Projection Matrix 等を作り直します。
Retina Display に対応するには (1) の
[self setWantsBestResolutionOpenGLSurface:YES]
を追加します。
この場合 OpenGL からは 4 倍の解像度に見えることになります。
resize 時もサイズ調整が必要で、(1.1) の
[self convertRectToBacking:brect] が変換を行っています。
同じように Mouse Event 等の座標を GL 座標に合わせるには
[self convertPointToBacking:pos] を使います。
当初 Window の Resize に GLView が追従してきませんでした。
設定を比べた結果、Use Autolayout を外すと View の Autosizing を
設定できるようになりました。

↓

wgl/egl のような初期設定がなく NSOpenGLView は非常に簡単でした。
ただし initWithFrame の Profile 指定にあるように OS X 10.8
では OpenGL 3.2 までしか対応していないようです。
NSOpenGLProfileVersion3_2Core は NSOpenGL.h で定義されています。
10.9 から OpenGL 4 対応になるらしいので、GL4 の新しい
機能を使うには OS のサポートを待つ必要があります。
以前 Nexus 7 (Ubuntu) で動かしていたプログラム↓も移植できました。

2013/09/26
iOS7 の世代交代と iPad2/iPad mini の対応画面解像度
iOS7 では iPad mini/iPad 2 の iPhone アプリの解像度が上がっています。
これまでの iOS6 の対応デバイスと対応する画面解像度は下記の通り。
iPhone 3GS は iOS6 唯一の 3.5inch 非retina デバイスですが、
iPad2/iPad mini も iPhone アプリを起動すると 3.5 非retina 相当の
表示になっていました。
iOS 7.0 は下記の通り。
3.5inch 非retina を表示するデバイスが無くなりました。
iPad2/iPad mini の場合は 1x の等倍切り替えが無い代わりに、
3.5 inch retina 相当で表示されるようになっています。
iPhone の retina 対応ゲームが遊びやすくなりました。
もしアプリを iOS 7 以上専用にするなら開発側の負担も減らすことが出来ます。
同時に iOS7 対応デバイスはどれも RAM 512MB 以上になっています。
その他のスペックは下記の通り。(wikipedia: List of iOS devices)
iPhone 4 以外はすべて Cortex-A9 以上の dula core CPU です。
GPU も同様にiPhone 4 を除いて 5XT の MP となっています。
互換性を考えると iOS7 専用はまだ早いかもしれませんが、
開発時に想定すべきハードウエアスペックは順当に世代交代が進んでいる
ことがわかります。
関連エントリ
・iPhone 5s A7 64bit CPU と AArch64 (arm64)
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・iPhone 5s の Apple A7 GPU
これまでの iOS6 の対応デバイスと対応する画面解像度は下記の通り。
iOS6 3.5 3.5R 4.0R HD HD-R RAM 480x320 960x640 1136x640 1024x768 2048x1536 ---------------------------------------------------------------- iPhone 3GS 256M ◎ -- -- -- -- iPhone 4 512M -- ◎ -- -- -- iPhone 4S 512M -- ◎ -- -- -- iPhone 5 1G -- -- ◎ -- -- iPod touch 4 256M -- ◎ -- -- -- iPod touch 5 512M -- -- ◎ -- -- iPad2 512M ◎ -- -- ◎ -- iPad3 1G -- ◎ -- -- ◎ iPad4 1G -- ◎ -- -- ◎ iPod mini 512M ◎ -- -- ◎ --
iPhone 3GS は iOS6 唯一の 3.5inch 非retina デバイスですが、
iPad2/iPad mini も iPhone アプリを起動すると 3.5 非retina 相当の
表示になっていました。
iOS 7.0 は下記の通り。
iOS7 3.5 3.5R 4.0R HD HD-R RAM 480x320 960x640 1136x640 1024x768 2048x1536 ---------------------------------------------------------------- iPhone 4 512M -- ◎ -- -- -- iPhone 4S 512M -- ◎ -- -- -- iPhone 5 1G -- -- ◎ -- -- iPhone 5c 1G -- -- ◎ -- -- iPhone 5s 1G -- -- ◎ -- -- iPod touch 5 512M -- -- ◎ -- -- iPad2 512M -- ◎ -- ◎ -- iPad3 1G -- ◎ -- -- ◎ iPad4 1G -- ◎ -- -- ◎ iPod mini 512M -- ◎ -- ◎ --
3.5inch 非retina を表示するデバイスが無くなりました。
iPad2/iPad mini の場合は 1x の等倍切り替えが無い代わりに、
3.5 inch retina 相当で表示されるようになっています。
iPhone の retina 対応ゲームが遊びやすくなりました。
もしアプリを iOS 7 以上専用にするなら開発側の負担も減らすことが出来ます。
同時に iOS7 対応デバイスはどれも RAM 512MB 以上になっています。
その他のスペックは下記の通り。(wikipedia: List of iOS devices)
iOS7 RAM SoC CPU GPU PVR Series ---------------------------------------------------------------- iPhone 4 512M A4 Cortex-A8 x1 PowerVR SGX535 5 iPhone 4S 512M A5 Cortex-A9 x2 PowerVR SGX543MP2 5XT iPhone 5 1G A6 Swift x2 PowerVR SGX543MP3 5XT iPhone 5c 1G A6 Swift x2 PowerVR SGX543MP3 5XT iPhone 5s 1G A7 A7 64bit x2 PowerVR G6430? 6? iPod touch 5 512M A5 Cortex-A9 x2 PowerVR SGX543MP2 5XT iPad2 512M A5 Cortex-A9 x2 PowerVR SGX543MP2 5XT iPad3 1G A5X Cortex-A9 x2 PowerVR SGX543MP4 5XT iPad4 1G A6X Swift x2 PowerVR SGX554MP4 5XT iPod mini 512M A5 Cortex-A9 x2 PowerVR SGX543MP2 5XT
iPhone 4 以外はすべて Cortex-A9 以上の dula core CPU です。
GPU も同様にiPhone 4 を除いて 5XT の MP となっています。
互換性を考えると iOS7 専用はまだ早いかもしれませんが、
開発時に想定すべきハードウエアスペックは順当に世代交代が進んでいる
ことがわかります。
armv6 ARM11 PVR MBX 4 3G/touch2 armv7 Cortex-A8 PVR SGX535 5 3GS/4/touch3/4/iPad armv7 Cortex-A9 PVR SGX543MP 5XT 4S/touch5/iPad2/3/mini armv7s Swift PVR SGX543MP/554MP 5XT 5/5c/iPad4 arm64 A7 64bit PVR 6 6 5s
関連エントリ
・iPhone 5s A7 64bit CPU と AArch64 (arm64)
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・iPhone 5s の Apple A7 GPU
2013/09/25
iPhone 5s A7 64bit CPU と AArch64 (arm64)
スマートフォンが搭載しているメモリ容量は非常に速いペースで増加しています。
下記ページに日本で発売された端末のスペックを集めています。
・端末全リスト: 日本で発売されたスマートフォン・タブレット全リスト
ざっと眺めただけでもだいたいこんな感じ↓でしょうか。
特に Android デバイスで容量増加が著しいことがわかります。
このペースが今後も続くと考えるならば、来年には 32bit プロセッサの
壁にぶつかることになります。
RAM 容量が必要になる原因の一つとして画面の高解像度化が考えられます。
こちらも RAM 増量に負けないペースで進化してきました。
高解像度化に伴いアプリケーションで必要な描画リソース量も増加します。
解像度が高いと 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 の方が命令数が
減ってコンパクトになっていることに気が付きます。
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
上記のように ARMv7 では互換性の問題から softfp (soft-float) が
使われることがありました。
浮動小数点値も関数入出力では一旦整数レジスタを経由しており無駄が発生します。
AArch64 (64bit) ではこのような配慮が不要なので最初から hard-float 相当
となっているようです。
64bit 化が直接的な理由ではありませんが、
ABI やスタックフレームの改良ができることも実パフォーマンスに
影響を与えているのではないかと思います。
実際に Windows の x86/x64 でも、両方使っていると
同じ CPU 上でも明らかに 64bit の方が速いことに気が付きます。
64bit が苦手と言われていた Core 2 でもきちんと効果がでていました。
・CPU ベンチ
x64 でレジスタ数が倍増したことが一番の要因かもしれませんが、
ABI のようにソフトウエアのデザイン面で互換性保たなくて良いことも
大きなメリットになっていると考えられます。
iPhone のメモリ空間にはまだ余裕がありますが、
パフォーマンスの向上や、利用効率を上げて省電力につなげるという
意味でも iPhone 5s の 64bit 化は意味があるように思います。
昨日 ARMv8 AArch64 の浮動小数点演算速度比較のためにコンパイラの
出力コードを調べていたのですが、これ↓が最初なにかわかりませんでした。
意味のない or 命令はレジスタ間の move でした。(mov v5,v1)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
・iPhone 5s の Apple A7 GPU
下記ページに日本で発売された端末のスペックを集めています。
・端末全リスト: 日本で発売されたスマートフォン・タブレット全リスト
ざっと眺めただけでもだいたいこんな感じ↓でしょうか。
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 の方が命令数が
減ってコンパクトになっていることに気が付きます。
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
上記のように 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 でもきちんと効果がでていました。
・CPU ベンチ
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 の浮動小数点演算速度 (32bit)
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
・iPhone 5s の Apple A7 GPU
64bit mode (AArch64) で走らせてみました。
命令もレジスタの構造も異なるのでコードは別物です。
検証が不完全で、この結果には間違いが含まれている可能性があります。
scalar 演算は予想通り AArch64 の方が高速に実行できるようです。
AArch64 では NEON に統合されていると考えられるため
vector 時と同等になっています。
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: は下記の通り。
レジスタ番号が一致しているので非常に書きやすくなりました。
関連ページ
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・2013/04/08:Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・2013/01/09:Qualcomm APQ8064 GPU Adreno 320 の速度
・2012/12/23:Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
命令もレジスタの構造も異なるのでコードは別物です。
検証が不完全で、この結果には間違いが含まれている可能性があります。
(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 では NEON に統合されていると考えられるため
vector 時と同等になっています。
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]
レジスタ番号が一致しているので非常に書きやすくなりました。
関連ページ
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・2013/04/08:Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・2013/01/09:Qualcomm APQ8064 GPU Adreno 320 の速度
・2012/12/23:Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
2013/09/23
iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
iPhone 5s の浮動小数点演算速度を命令単位で比べてみました。
A7 の CPU core は ARMv8 で 64bit 命令に対応していますが、
ここでの比較は AArch32 (32bit mode) の VFP/NEON 命令となっています。
64bit mode (AArch64) ではレジスタの個数や view が異なるので
違う結果になる可能性があります。
速いと思った iPhone 5 A6 の Swift から 1年、A7 はさらに強力な演算能力を
持っているようです。
ほぼ同クロック(?)でも最大で Swift の 3倍のスループットとなっており、
クロック差があるにも関わらず Cortex-A15 に匹敵するスコアが出ているようです。
特に NEON 命令が高速であることがわかります。
D と Q で差がないので、演算は 128bit 単位だと考えられます。
それでも Cortex-A15 の 64bit 2pipe で実現している速度に追いついているので、
あくまで憶測ですが A7 は 128bit pipe が複数存在している可能性があります。
反面、VFP の方は他の CPU とあまり違いが無いようで、
動作クロックの分だけ差がついています。
ただし Swift で極端に苦手だったスカラーの積和命令においては、
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 を含めて多くの機種の結果を下記のページにまとめました。
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
関連エントリ
・2013/04/08:Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・2013/01/09:Qualcomm APQ8064 GPU Adreno 320 の速度
・2012/12/23:Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
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 で極端に苦手だったスカラーの積和命令においては、
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 を含めて多くの機種の結果を下記のページにまとめました。
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
関連エントリ
・2013/04/08:Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・2013/01/09:Qualcomm APQ8064 GPU Adreno 320 の速度
・2012/12/23:Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
2013/09/22
iPhone 5s の Apple A7 GPU
A7 の GPU は「Apple A7 GPU」と表示されており独自の名前が付けられています。
PVRTC に対応しているため PowerVR 系である可能性は高くなっています。
ですが PVRTC(v2) が無く汎用性の高い ETC2/EAC に置き換わっていることもあり、
PowerVR 依存からの方針転換が見て取れるように思います。
・OpenGL ES Extension (Mobile GPU)
Mali-T604, Adreno 320 との比較です。(参考)
これまでと違う 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 系と同じ値を返してくるようです。
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 で追加されたのかもしれません。
・OpenGL ES Graphics
上記にも書かれていますが glGetShaderPrecisionFormat() の結果に違いが見られます。
float lowp が mediump と同じ fp16 で、int highp も 32bit になっています。
下記ページも更新しました。
・GPU Precision まとめ
ただし上のページにも書いているように API で得られる仕様と
実際の演算結果は異なっていることがあります。
同じ fix10 でも、PowerVR series 5 (SGX535/540) & Tegra2/3 と
series 5XT (SGX543MP/554MP) ではシェーディング結果に差が生じています。
5XT の方が Fragment だけ lowp の精度が高くなっているように見えます。
A7 GPU の場合は最初から fp16 なので、
互換性の意味でも都合の良い仕様だと思います。
関連エントリ
・iOS7 と iPhone 5s の sRGB 対応とテクスチャフォーマット
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・OpenGL ES 2.0 GLSL precision 宣言と GPU 毎の演算精度を調べる
・GPU Precision まとめ
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 依存からの方針転換が見て取れるように思います。
・OpenGL ES Extension (Mobile GPU)
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 で追加されたのかもしれません。
・OpenGL ES Graphics
上記にも書かれていますが glGetShaderPrecisionFormat() の結果に違いが見られます。
float lowp が mediump と同じ fp16 で、int highp も 32bit になっています。
下記ページも更新しました。
・GPU Precision まとめ
ただし上のページにも書いているように API で得られる仕様と
実際の演算結果は異なっていることがあります。
同じ fix10 でも、PowerVR series 5 (SGX535/540) & Tegra2/3 と
series 5XT (SGX543MP/554MP) ではシェーディング結果に差が生じています。
5XT の方が Fragment だけ lowp の精度が高くなっているように見えます。
A7 GPU の場合は最初から fp16 なので、
互換性の意味でも都合の良い仕様だと思います。
関連エントリ
・iOS7 と iPhone 5s の sRGB 対応とテクスチャフォーマット
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・OpenGL ES 2.0 GLSL precision 宣言と GPU 毎の演算精度を調べる
・GPU Precision まとめ
2013/09/21
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 で
同等の相互変換がサポートされました。(下記ページも更新)
・OpenGL ES Extension (Mobile GPU)
例えば 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
前回の表↓を更新しました。
iOS が対応しているフォーマットは PVRTC (v1) だけで PVRTC2 (v2) は
含まれていないようです。
またフレームバッファに対するリニアからの変換 (GL_EXT_sRGB) も
サポートしています。
iOS はもともと Renderbuffer を直接作っていたので、EGL/WGL のような
機能選択が不要です。
さらに GLK (GLKit) なら 1行変えるだけで対応できてしまい、
Android での苦労が嘘のように簡単でした。
PowerVR SGX535 (iPhone4) は未確認ですが、SGX543MP/554MP では
iOS 7.0 で Apple A7 GPU と同じように動作していることを確認しています。
●テクスチャフォーマット
iOS でも OpenGL ES 3.0 では Android 同様 ETC2/EAC が利用できるように
なっています。
Android など他の環境と互換性を保ちやすくなりました。
Android のすべての端末と iOS ES 3.0 以降は ETC1 の読み出しができます。
Android/iOS 区別なく OpenGL ES 3.0 デバイスでは、
いまのところすべて ETC2/EAC を使うことが出来ます。
関連エントリ
・OpenGL と sRGB
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 で
同等の相互変換がサポートされました。(下記ページも更新)
・OpenGL ES Extension (Mobile GPU)
例えば 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) なら 1行変えるだけで対応できてしまい、
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 を使うことが出来ます。
関連エントリ
・OpenGL と sRGB
2013/09/05
OpenGL と sRGB
一般的な画像はモニタに合わせてガンマ補正した非線形なデータになっています。
そのまま演算に用いると正しい結果が得られないため、事前にリニア値への
変換が必要になります。
同様に出力時は元のモニタ用の色空間に戻します。
・入力時 sRGB → Linear 変換
・出力時 Linear → sRGB 変換
OpenGL (2.1/3.0) や OpenGL ES 3.0 以降は標準である sRGB 色空間に対応しており、
リニア値との相互変換ができるようになっています。
変換が行われるのは上記のようにテクスチャの読み込みと、フレームバッファへの
書き込みのタイミングです。
●入力時
intenal format に sRGB 形式であることを指定できます。
テクスチャフェッチで同時に Linear に展開されます。
圧縮フォーマットも同様です。
変換は RGB のみで Alpha は含まれません。
OpenGL 4.x RADEON/GeForce/Intel HD 4000、OpenGL ES 3.0 Mali-T604 で
動作を確認しています。
OpenGL ES 2.0 で用いられていた GPU 固有の圧縮フォーマットには sRGB 形式が
定義されていないものがあります。
現在わかっている情報からまとめると下記の通り。
ETC1 に対応する sRGB フォーマットがありませんが、ETC2 が上位互換なので
GL_COMPRESSED_SRGB8_ETC2 で読み込むことが出来ます。
OpenGL ES 3.0 GPU は ETC2/EAC に対応しているので、SRGB 形式が必要なら
ETC2 を選択することになるかと思います。
フィルタリングに関与できないので厳密ではありませんが、
シェーダーで Linear に変換することも可能です。
ガンマ補正はデータ圧縮の一種といえるので、sRGB 8bit を展開すると
リニア値は 8bit 以上の精度が必要となります。
●出力時
フレームバッファが sRGB 形式で作られている場合、書き込み時に変換が行われます。
自分で作る場合は簡単で、Texture 同様に internal format に sRGB 形式を指定します。
OS が用意する Default Framebuffer の場合は wgl や egl を用いて
SRGB 対応のフォーマットを選んでおく必要があります。
ただし Windows 7/8 + RADEON/GeForce では、特に何もしなくても SRGB 形式となっており
glEnable( GL_FRAMEBUFFER_SRGB ) だけで意図した結果が得られるようです。
逆に Intel HD 4000 (9.18.10.3165) では、下記の方法で SRGB バッファを選択しても
Default Framebuffer での変換がうまく出来ませんでした。
wgl を使った選択手段は下記のとおり。
1. wgl extension の wglChoosePixelFormatARB() を取得
2. 必要なパラメータ(attribute) を指定して wglChoosePixelFormatARB() で候補を選ぶ
3. 得られた Config 値を SetPixelFormat() に渡す
Intel HD 4000 でも自分で Framebuffer を用意した場合は
glEnable( GL_FRAMEBUFFER_SRGB ) の設定が結果に影響を与えていることを確認できます。
ただし OpenGL 4.0 では結果をそのまま出力する手段が見つかりませんでした。
glBlitFramebuffer() や Texture としての読み込みは、ソースが sRGB の場合に
リニア変換されてしまうので、元が Linear か sRGB か区別出来ないからです。
よって Default Framebuffer に転送する場合にシェーダーでもう一度再エンコードが
必要となります。
OpenGL 4.2 以降ならメモリイメージとして転送できるので、もっと良い方法が
あるかもしれません。
OpenGL ES 3.0 (Mali-T604) では GL_FRAMEBUFFER_SRGB による切り替えが
できないので、Framebuffer に対して正しく変換されているかどうか確認できませんでした。
SRGB はブレンドの結果に影響を与えるので、ブレンド結果を比べれば
機能していること確認できるのではないかと思っています。
入力側は容易でしたが、出力側は必ずしも統一した挙動になってくれないようです。
Framebuffer が HDR の場合リニアのまま格納できるので、互換性を考えると
最終的にシェーダーで変換するのが一番なのかもしれません。
関連エントリ
・OpenGL 3.x/4.x のシェーダー GLSL とメモリアクセス命令
・OpenGL 4.x Program Pipeline Object (Separate Shader Object)
・OpenGL 4.2/4.3 Shader Resource と Buffer API
・OpenGL ES 3.0/OpenGL 4.x Uniform Block
・OpenGL の各バージョンと GLSL の互換性
・OpenGL のエラー判定と OpenGL 4.3 Debug Output
・OpenGL ES 3.0/OpenGL 4.4 Texture Object と Sampler Object
・OpenGL ES 3.0 と Vertex Array Object
そのまま演算に用いると正しい結果が得られないため、事前にリニア値への
変換が必要になります。
同様に出力時は元のモニタ用の色空間に戻します。
・入力時 sRGB → Linear 変換
・出力時 Linear → sRGB 変換
OpenGL (2.1/3.0) や OpenGL ES 3.0 以降は標準である sRGB 色空間に対応しており、
リニア値との相互変換ができるようになっています。
変換が行われるのは上記のようにテクスチャの読み込みと、フレームバッファへの
書き込みのタイミングです。
●入力時
intenal format に sRGB 形式であることを指定できます。
テクスチャフェッチで同時に Linear に展開されます。
圧縮フォーマットも同様です。
// Linear glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_ETC2, w, h, 0, size, data ); glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, w, h, 0, size, data ); // sRGB glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_COMPRESSED_SRGB8_ETC2, w, h, 0, size, data ); glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, w, h, 0, size, data );
変換は RGB のみで Alpha は含まれません。
OpenGL 4.x RADEON/GeForce/Intel HD 4000、OpenGL ES 3.0 Mali-T604 で
動作を確認しています。
OpenGL ES 2.0 で用いられていた GPU 固有の圧縮フォーマットには sRGB 形式が
定義されていないものがあります。
現在わかっている情報からまとめると下記の通り。
OpenGL ES 3.0 での sRGB ---------------------------------------- ETC1 あり(ETC2) ETC2 あり PVRTC 無し (PowerVR のみ) PVRTC2 無し (PowerVR のみ) ATITC 無し (Adreno のみ) ASTC あり S3TC(DXT1) あり
ETC1 に対応する sRGB フォーマットがありませんが、ETC2 が上位互換なので
GL_COMPRESSED_SRGB8_ETC2 で読み込むことが出来ます。
OpenGL ES 3.0 GPU は ETC2/EAC に対応しているので、SRGB 形式が必要なら
ETC2 を選択することになるかと思います。
フィルタリングに関与できないので厳密ではありませんが、
シェーダーで Linear に変換することも可能です。
ガンマ補正はデータ圧縮の一種といえるので、sRGB 8bit を展開すると
リニア値は 8bit 以上の精度が必要となります。
●出力時
フレームバッファが sRGB 形式で作られている場合、書き込み時に変換が行われます。
自分で作る場合は簡単で、Texture 同様に internal format に sRGB 形式を指定します。
// Renderbuffer glGenRenderbuffers( 1, &ColorBuffer ); glBindRenderbuffer( GL_RENDERBUFFER, ColorBuffer ); glRenderbufferStorage( GL_RENDERBUFFER, GL_SRGB8_ALPHA8, w, h ); glBindRenderbuffer( GL_RENDERBUFFER, 0 ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, FrameBuffer ); glFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ColorBuffer ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); // Texture glGenTextures( 1, &ColorTexture ); glBindTexture( GL_TEXTURE_2D, ColorTexture ); glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glBindTexture( GL_TEXTURE_2D, 0 ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, FrameBuffer ); glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ColorTexture, 0 ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
OS が用意する Default Framebuffer の場合は wgl や egl を用いて
SRGB 対応のフォーマットを選んでおく必要があります。
ただし Windows 7/8 + RADEON/GeForce では、特に何もしなくても SRGB 形式となっており
glEnable( GL_FRAMEBUFFER_SRGB ) だけで意図した結果が得られるようです。
逆に Intel HD 4000 (9.18.10.3165) では、下記の方法で SRGB バッファを選択しても
Default Framebuffer での変換がうまく出来ませんでした。
wgl を使った選択手段は下記のとおり。
1. wgl extension の wglChoosePixelFormatARB() を取得
2. 必要なパラメータ(attribute) を指定して wglChoosePixelFormatARB() で候補を選ぶ
3. 得られた Config 値を SetPixelFormat() に渡す
static const int PixelFormat_Attr[]= { WGL_DRAW_TO_WINDOW_ARB, TRUE, WGL_SUPPORT_OPENGL_ARB, TRUE, WGL_DOUBLE_BUFFER_ARB, TRUE, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_COLOR_BITS_ARB, 32, WGL_RED_BITS_ARB, 8, WGL_GREEN_BITS_ARB, 8, WGL_BLUE_BITS_ARB, 8, WGL_ALPHA_BITS_ARB, 8, WGL_DEPTH_BITS_ARB, 24, WGL_STENCIL_BITS_ARB, 8, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE, 0 }; int ChooseConfig() { int pixelformat= 0; if( !p_wglChoosePixelFormatARB ){ // extension の確認 return ChoosePixelFormat( hDC, &PixelFormat_Default ); } const unsigned int FORMAT_ARRAY_SIZE= 16; int FormatArray[FORMAT_ARRAY_SIZE]; unsigned int array_size= 0; if( !wglChoosePixelFormatARB( hDC, PixelFormat_Attr, NULL, FORMAT_ARRAY_SIZE, FormatArray, &array_size ) ){ return 0; } return FormatArray[0]; } void SetPixelFormat() { int pixelformat= ChooseConfig(); if( !pixelformat ){ // error } SetPixelFormat( hDC, pixelformat, NULL ); }
Intel HD 4000 でも自分で Framebuffer を用意した場合は
glEnable( GL_FRAMEBUFFER_SRGB ) の設定が結果に影響を与えていることを確認できます。
ただし OpenGL 4.0 では結果をそのまま出力する手段が見つかりませんでした。
glBlitFramebuffer() や Texture としての読み込みは、ソースが sRGB の場合に
リニア変換されてしまうので、元が Linear か sRGB か区別出来ないからです。
よって Default Framebuffer に転送する場合にシェーダーでもう一度再エンコードが
必要となります。
OpenGL 4.2 以降ならメモリイメージとして転送できるので、もっと良い方法が
あるかもしれません。
OpenGL ES 3.0 (Mali-T604) では GL_FRAMEBUFFER_SRGB による切り替えが
できないので、Framebuffer に対して正しく変換されているかどうか確認できませんでした。
SRGB はブレンドの結果に影響を与えるので、ブレンド結果を比べれば
機能していること確認できるのではないかと思っています。
入力側は容易でしたが、出力側は必ずしも統一した挙動になってくれないようです。
Framebuffer が HDR の場合リニアのまま格納できるので、互換性を考えると
最終的にシェーダーで変換するのが一番なのかもしれません。
// GLSL const float SCALE_0= 1.0/12.92; const float SCALE_1= 1.0/1.055; const float OFFSET_1= 0.055 * SCALE_1; float SRGBToLinear_F( float color ) { if( color <= 0.04045 ){ return color * SCALE_0; } return pow( color * SCALE_1 + OFFSET_1, 2.4 ); } float LinearToSRGB_F( float color ) { color= clamp( color, 0.0, 1.0 ); if( color < 0.0031308 ){ return color * 12.92; } return 1.055 * pow( color, 0.41666 ) - 0.055; } vec3 LinearToSRGB_V( vec3 color ) { return vec3( LinearToSRGB_F( color.x ), LinearToSRGB_F( color.y ), LinearToSRGB_F( color.z ) ); } vec3 SRGBToLinear_V( vec3 color ) { return vec3( SRGBToLinear_F( color.x ), SRGBToLinear_F( color.y ), SRGBToLinear_F( color.z ) ); }
関連エントリ
・OpenGL 3.x/4.x のシェーダー GLSL とメモリアクセス命令
・OpenGL 4.x Program Pipeline Object (Separate Shader Object)
・OpenGL 4.2/4.3 Shader Resource と Buffer API
・OpenGL ES 3.0/OpenGL 4.x Uniform Block
・OpenGL の各バージョンと GLSL の互換性
・OpenGL のエラー判定と OpenGL 4.3 Debug Output
・OpenGL ES 3.0/OpenGL 4.4 Texture Object と Sampler Object
・OpenGL ES 3.0 と Vertex Array Object