Archives

September 2013 の記事

下記 CPU ベンチ の結果を更新しました。
この結果だけを見れば 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


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" に変更。

xcode_gl01.png

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

xcode_gl02.png

プロジェクトには 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 を
設定できるようになりました。

xcode_gl06.png



xcode_gl03.png

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) で動かしていたプログラム↓も移植できました。

xcode_gl05.png


iOS7 では iPad mini/iPad 2 の iPhone アプリの解像度が上がっています。
これまでの 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


スマートフォンが搭載しているメモリ容量は非常に速いペースで増加しています。
下記ページに日本で発売された端末のスペックを集めています。

端末全リスト: 日本で発売されたスマートフォン・タブレット全リスト

ざっと眺めただけでもだいたいこんな感じ↓でしょうか。

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) で走らせてみました。
命令もレジスタの構造も異なるのでコードは別物です。
検証が不完全で、この結果には間違いが含まれている可能性があります。

                  (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 の浮動小数点演算能力


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 で極端に苦手だったスカラーの積和命令においては、
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 の 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 依存からの方針転換が見て取れるように思います。

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 まとめ


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

前回の表↓を更新しました。

          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 に展開されます。
圧縮フォーマットも同様です。

// 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