Android NDK r9d の GLES2/gl2ext.h には、本来無いはずの "include gl2.h" が
追加されているために、OpenGL ES 3.0 と組み合わせて利用できなくなっています。
r9d で追加されたようです。
GLES3/gl3ext.h は中身が空なので、例えば GPU 固有のテクスチャフォーマット
PVR, ATC, DXT 等のシンボルを用いるには gl2ext.h を include する必要がありました。
とりあえずの対処としては、
Android の場合だけ __gl2_h_ を定義してしまう方法があります。
Android 以外や Khronos のヘッダファイルでは問題ありません。
関連エントリ
・Android NDK r9d の armeabi-v7a-hard と ABI
・iPhone 5s の Apple A7 GPU
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・OpenGL ES 3.0/OpenGL 4.x Uniform Block
追加されているために、OpenGL ES 3.0 と組み合わせて利用できなくなっています。
r9d で追加されたようです。
#include <GLES2/gl2.h>
GLES3/gl3ext.h は中身が空なので、例えば GPU 固有のテクスチャフォーマット
PVR, ATC, DXT 等のシンボルを用いるには gl2ext.h を include する必要がありました。
とりあえずの対処としては、
Android の場合だけ __gl2_h_ を定義してしまう方法があります。
#define __gl2_h_ // 追加
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
Android 以外や Khronos のヘッダファイルでは問題ありません。
関連エントリ
・Android NDK r9d の armeabi-v7a-hard と ABI
・iPhone 5s の Apple A7 GPU
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・OpenGL ES 3.0/OpenGL 4.x Uniform Block
OpenGL ES 3.1 の仕様が公開されました。
バージョン番号は 3 のままですが、内容は OpenGL 4.x の機能を
取り込んだ大幅なアップデートとなっています。
最近のハイエンド Mobile GPU は、Windows Tablet を想定して Direct3D 11
API も積極的にサポートしつつあります。
OpenGL ES 3.1 にはこれらの GPU の進化がそのまま反映されていると言えます。
・Khronos OpenGL ES Registry
ユニークなのは、OpenGL ES が GeometryShader や Tessellator 等の
組み込みのシェーダーパイプラインを採用しなかったことです。
その代わり柔軟で扱いやすい ComputeShader に仕様を絞り込んでおり、
機能と自由度のバランスを上手く保っている印象です。
より詳しい表はこちら↓
・GLSL Version
ComputeShader をサポートしたことで、同時にバッファのランダムアクセスや
読み書き、Atomic なオペレーション命令などもひと通り入りました。
どれも OpenGL 4.x 相当です。Indirect Draw もあります。
バッファアクセスについて詳しくは下記のエントリを参照してください。
・OpenGL 3.x/4.x のシェーダー GLSL とメモリアクセス命令
buffer 命令が増えたことで GLSL の layout() 構文も賑やかになりました。
これまで Uniform や Attribute のバインドには、OpenGL API を使って
Location を参照したり値を書き換える必要がありました。
GLES 3.1 (と OpenGL 4.3以降) は GLSL 内に直接数値で宣言できます。
また Direct3D のように実行時にシェーダーのステージを組み合わせられる
ようになります。詳細は下記をどうぞ。
・OpenGL 4.x Program Pipeline Object (Separate Shader Object)
Shader Stage は少ないものの、OpenGL ES 3.1 は OpenGL 4 の特徴を取り入れており
Direct3D との親和性(移植しやすさ) が向上していることがわかります。
OpenGL 4.x とのコード共有もしやすくなるのですが、
Desktop PC では Intel GPU が OpenGL 4.0~4.1 に留まっており、
上記の機能の多くを使うことができません。
OpenGL で ComputeShader を当たり前に使えるようになるには
まだ時間がかかりそうです。
OpenGL ES の GLSL が暗黙の型変換をサポートしないのは 3.1 でも同様で、
仕様となっています。
Uniform Block (Interface Block) の input/output はサポートされませんでした。
GLES3.1 は OpenGL ES 2.0/3.0 との上位互換性を保っています。
Mobile GPU が活発になってからは、バージョンが進むほど下位互換性が復活する
傾向があります。
OpenGL 3~4 もそうですし、Direct3D 10~11 も同様でした。
Mobile GPU が高機能になるにつれて、Desktop GPU 向け API と区別する
必要性はなくなりつつあります。
OpenGL を使う側の立場としても、最終的には統合して欲しい願っています。
ですが、WebGL のように軽量な API として用途が広がる可能性を考えると
ComputeShader に絞った仕様は良い選択かも知れません。
関連エントリ
・iPhone 5s の Apple A7 GPU
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・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
バージョン番号は 3 のままですが、内容は OpenGL 4.x の機能を
取り込んだ大幅なアップデートとなっています。
最近のハイエンド Mobile GPU は、Windows Tablet を想定して Direct3D 11
API も積極的にサポートしつつあります。
OpenGL ES 3.1 にはこれらの GPU の進化がそのまま反映されていると言えます。
・Khronos OpenGL ES Registry
世代毎の API OpenGL ES OpenGL Direct3D ShaderModel ------------------------------------------------------------- OpenGL ES 2.0 OpenGL 2.1 Direct3D9 ShaderModel 3.0 OpenGL ES 3.0 OpenGL 3.3 Direct3D10.1 ShaderModel 4.1 OpenGL ES 3.1 OpenGL 4.4 Direct3D11.2 ShaderModel 5.0
ユニークなのは、OpenGL ES が GeometryShader や Tessellator 等の
組み込みのシェーダーパイプラインを採用しなかったことです。
その代わり柔軟で扱いやすい ComputeShader に仕様を絞り込んでおり、
機能と自由度のバランスを上手く保っている印象です。
機能の比較 Shader Version ------------------------------------------------------------ OpenGL ES 2.0 vsh fsh --- --- --- --- #version 100 OpenGL ES 3.0 vsh fsh --- --- --- --- #version 300 es OpenGL ES 3.1 vsh fsh --- --- --- csh #version 310 es OpenGL 2.1 vsh fsh --- --- --- --- #version 120 OpenGL 3.3 vsh fsh gsh --- --- --- #version 330 OpenGL 4.4 vsh fsh gsh tcsh tesh csh #version 440 Direct3D 9 vsh psh --- --- --- --- 3.0 Direct3D 10 vsh psh gsh --- --- --- 4.0 Direct3D 11 vsh psh gsh hsh dsh csh 5.0
より詳しい表はこちら↓
・GLSL Version
ComputeShader をサポートしたことで、同時にバッファのランダムアクセスや
読み書き、Atomic なオペレーション命令などもひと通り入りました。
どれも OpenGL 4.x 相当です。Indirect Draw もあります。
Texture Image Load and Store OpenGL 4.2 Atomic Counter Buffer OpenGL 4.2 Shader Storage Buffer OpenGL 4.3 Shared Memory OpenGL 4.3
バッファアクセスについて詳しくは下記のエントリを参照してください。
・OpenGL 3.x/4.x のシェーダー GLSL とメモリアクセス命令
buffer 命令が増えたことで GLSL の layout() 構文も賑やかになりました。
これまで Uniform や Attribute のバインドには、OpenGL API を使って
Location を参照したり値を書き換える必要がありました。
GLES 3.1 (と OpenGL 4.3以降) は GLSL 内に直接数値で宣言できます。
また Direct3D のように実行時にシェーダーのステージを組み合わせられる
ようになります。詳細は下記をどうぞ。
・OpenGL 4.x Program Pipeline Object (Separate Shader Object)
Shader Stage は少ないものの、OpenGL ES 3.1 は OpenGL 4 の特徴を取り入れており
Direct3D との親和性(移植しやすさ) が向上していることがわかります。
OpenGL 4.x とのコード共有もしやすくなるのですが、
Desktop PC では Intel GPU が OpenGL 4.0~4.1 に留まっており、
上記の機能の多くを使うことができません。
OpenGL で ComputeShader を当たり前に使えるようになるには
まだ時間がかかりそうです。
OpenGL ES の GLSL が暗黙の型変換をサポートしないのは 3.1 でも同様で、
仕様となっています。
Uniform Block (Interface Block) の input/output はサポートされませんでした。
GLES3.1 は OpenGL ES 2.0/3.0 との上位互換性を保っています。
Mobile GPU が活発になってからは、バージョンが進むほど下位互換性が復活する
傾向があります。
OpenGL 3~4 もそうですし、Direct3D 10~11 も同様でした。
Mobile GPU が高機能になるにつれて、Desktop GPU 向け API と区別する
必要性はなくなりつつあります。
OpenGL を使う側の立場としても、最終的には統合して欲しい願っています。
ですが、WebGL のように軽量な API として用途が広がる可能性を考えると
ComputeShader に絞った仕様は良い選択かも知れません。
関連エントリ
・iPhone 5s の Apple A7 GPU
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
・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
2014/03/15
Android NDK r9d の armeabi-v7a-hard と ABI
Android NDK r9d では、新しく APP_ABI に armeabi-v7a-hard が追加されました。
とはいえ端末側の ABI の種類が増えたわけではなく、hard-float を指定した
バイナリのビルドがより簡単に行えるようになります。
・Android NDK
r9b/r9c では hard-float を使うために jni/Android.mk に直接オプションを
記述していました。
r9d からは上記のような Android.mk の修正が不要になります。
APP_ABI に armeabi-v7a-hard を指定するだけで hard-float に対応します。
例えば ndk-build コマンドの引数で与えるなら下記の通り。
jni/Application.mk に書いておくなら下記の通り。
APP_ABI:=all ではデフォルトの armeabi-v7a とみなされるので、
hard-float を使う場合は上記のように全部列挙しておく必要があります。
Android OS 側は softfp のままなので、hard-float が有効なのはあくまで
アプリケーション内の関数呼び出しに限定されます。
例えば OpenGL ES のような浮動小数点パラメータを持つ System API の
呼び出しは、これまでどおり softfp が用いられます。
hard-float といいつつ厳密には softfp も混在していることになります。
そのため OS から見れば従来のアプリケーションと全く同じなので、
バイナリを区別する必要がありません。
armeabi-v7a-hard でビルドしたバイナリも libs/armaebi-v7a に入ります。
他の APP_ABI と違い、armeabi-v7a と armeabi-v7a-hard の 2種類生成する
わけではないのでご注意ください。
どちら片方を選択します。
互換性が問題になるケースはおそらく外部ライブラリ利用時でしょう。
リンクするライブラリも下記いずれかの方法で hard-float に対応している
必要があります。
ライブラリの hard-float 対応手段は二通りあります。
(1) ライブラリも hard-float でビルドする
(2) ヘッダファイルに softfp 指定 __NDK_FPABI__ を追加する
(1) の場合は spftfp 版と hard-float 版ライブラリの両方を用意しておく
必要があります。
(2) はヘッダの関数宣言時に softfp 呼び出しを意味する __NDK_FPABI__ を
記述しておきます。(中身は __attribute__((pcs("aapcs"))) )
この場合ライブラリは softfp 一種類だけです。
NDK の hard-float について詳しくは下記も参照してください。
・Android NDK r9b と ARMv7A の hard-float
Android NDK で使用可能な ABI 指定のまとめ。
ARM 以外は最初から FPU 必須で hard-float 相当です。
ちなみに ios は下記の通り。
soft-float, softfp, hard-float の違い。
関連エントリ
・Android NDK r9b と ARMv7A の hard-float
・iPhone 5s A7 64bit CPU と AArch64 (arm64)
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
とはいえ端末側の ABI の種類が増えたわけではなく、hard-float を指定した
バイナリのビルドがより簡単に行えるようになります。
・Android NDK
r9b/r9c では hard-float を使うために jni/Android.mk に直接オプションを
記述していました。
# android-ndk-r9b/r9c
# jni/Android.mk
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS+= -mhard-float -D_NDK_MATH_NO_SOFTFP=1
LOCAL_LDLAGS+= -lm_hard -Wl,--no-warn-mismatch
endif
# jni/Android.mk
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS+= -mhard-float -D_NDK_MATH_NO_SOFTFP=1
LOCAL_LDLAGS+= -lm_hard -Wl,--no-warn-mismatch
endif
r9d からは上記のような Android.mk の修正が不要になります。
APP_ABI に armeabi-v7a-hard を指定するだけで hard-float に対応します。
例えば ndk-build コマンドの引数で与えるなら下記の通り。
ndk-build APP_ABI=armeabi-v7a-hard
jni/Application.mk に書いておくなら下記の通り。
# jni/Application.mk
APP_ABI:= armeabi-v7a-hard armeabi x86 mips
APP_ABI:= armeabi-v7a-hard armeabi x86 mips
APP_ABI:=all ではデフォルトの armeabi-v7a とみなされるので、
hard-float を使う場合は上記のように全部列挙しておく必要があります。
Android OS 側は softfp のままなので、hard-float が有効なのはあくまで
アプリケーション内の関数呼び出しに限定されます。
例えば OpenGL ES のような浮動小数点パラメータを持つ System API の
呼び出しは、これまでどおり softfp が用いられます。
hard-float といいつつ厳密には softfp も混在していることになります。
そのため OS から見れば従来のアプリケーションと全く同じなので、
バイナリを区別する必要がありません。
armeabi-v7a-hard でビルドしたバイナリも libs/armaebi-v7a に入ります。
他の APP_ABI と違い、armeabi-v7a と armeabi-v7a-hard の 2種類生成する
わけではないのでご注意ください。
どちら片方を選択します。
互換性が問題になるケースはおそらく外部ライブラリ利用時でしょう。
リンクするライブラリも下記いずれかの方法で hard-float に対応している
必要があります。
ライブラリの hard-float 対応手段は二通りあります。
(1) ライブラリも hard-float でビルドする
(2) ヘッダファイルに softfp 指定 __NDK_FPABI__ を追加する
(1) の場合は spftfp 版と hard-float 版ライブラリの両方を用意しておく
必要があります。
(2) はヘッダの関数宣言時に softfp 呼び出しを意味する __NDK_FPABI__ を
記述しておきます。(中身は __attribute__((pcs("aapcs"))) )
この場合ライブラリは softfp 一種類だけです。
float fpfunc( float a, float b ) __NDK_FPABI__;
NDK の hard-float について詳しくは下記も参照してください。
・Android NDK r9b と ARMv7A の hard-float
Android NDK で使用可能な ABI 指定のまとめ。
armeabi ARMv5TE FPU 無し soft-float armeabi-v7a ARMv7A VFPv3-D16 softfp armeabi-v7a-hard ARMv7A VFPv3-D16 hard-float (softfp混在) x86 x86 SSSE3 hard-float mips MIPS32R1 FPU hard-float
ARM 以外は最初から FPU 必須で hard-float 相当です。
ちなみに ios は下記の通り。
armv6 ARMv6 VFPv2-D16 softfp armv7 ARMv7A VFPv3-D32 NEON softfp armv7s ARMv7A VFPv4-D32 NEON spftfp arm64 ARMv8 AArch64 NEON hard-float
soft-float, softfp, hard-float の違い。
FPU 浮動小数点演算 関数パラメータ --------------------------------------------------------------------- soft-float FPU無し soft/ライブラリ呼び出し 整数レジスタ経由 softfp FPUあり hard/FPU が行う 整数レジスタ経由 hard-float FPUあり hard/FPU が行う 浮動小数点レジスタ直接
関連エントリ
・Android NDK r9b と ARMv7A の hard-float
・iPhone 5s A7 64bit CPU と AArch64 (arm64)
・Nexus 7 の Ubuntu で ARM の abi softfp と hard-float を比べる
Desktop GPU で Vertex Shader と Pixel Shader の仕様が完全に
統一されたのは Direct3D 10 の ShaderModel 4.0 からです。
それまでは使える命令や Constant 領域、レジスタ数、プログラムサイズ、
テクスチャ命令など様々な違いが残っていました。
Hardware の Unified Shader 化は ATI の Xbox360 GPU が先行しています。
これが今の Qualcomm Adreno に繋がっていきます。
その後一般の Desktop PC 向けにも NVIDIA GeForce 8800 (G80) が登場し、
以後 Unified Shader model が当たり前となっています。
OpenGL ES 2.0 の Shader 世代は Direct3D 9 の Shader Model 3.0 に相当
するのですが、Mobile GPU の多くはすでに Unified Shader です。
そのためあまり Vertex と Fragment Shader の機能差を意識する必要が
ありませんでした。
そんな中、Tegra2/3/4 は G70 ベースの GPU であり、Unified Shader 化する前の
制限が残っている珍しいケースとなっています。
コメントで Tegra の Fragment Shader は動的ループが使えないとの
指摘を頂いたので試してみました。
↑ループ回数を動的に求めた場合、Vertex Shader は通りますが
Fragment Shader ではコンパイル時にエラーが発生します。
以前書いたように Uniform 配列の index アクセス ↓(2) も
Tegra の Fragment Shader ではエラーとなります。
どちらも Direct3D 9 世代の制限と考えられます。
Tegra 4 でも同様なので、大幅に機能拡張されていても GPU のベースは
同じであることがわかります。
なお Tegra と同じように Discrete Type の Shader Unit を備える
Mai-400MP では動きました。
ただし Tegra でも動的分岐はできるので、実行時にループ回数が変動する
場合でも同等の処理を実現することは可能です。
以下まとめ (いずれも Fragment Shader の場合)
コンパイル時にループ回数が定まらない場合はエラー。
ループの範囲が決まっていればコンパイル可能。
おそらく下記のように展開されているものと考えられます。
Tegra K1 以降は ShaderModel 5.0 世代の GPU core になるので
このようなハードウエア的な制限はなくなるでしょう。
GPU 互換性など気軽に相談してください。
関連エントリ
・OpenGL ES 2.0 Adreno 330, Tegra 4 の GPU 速度
・OpenGL ES 2.0 で迷路シェーダー
・GLSL互換性
統一されたのは Direct3D 10 の ShaderModel 4.0 からです。
それまでは使える命令や Constant 領域、レジスタ数、プログラムサイズ、
テクスチャ命令など様々な違いが残っていました。
Hardware の Unified Shader 化は ATI の Xbox360 GPU が先行しています。
これが今の Qualcomm Adreno に繋がっていきます。
その後一般の Desktop PC 向けにも NVIDIA GeForce 8800 (G80) が登場し、
以後 Unified Shader model が当たり前となっています。
OpenGL ES 2.0 の Shader 世代は Direct3D 9 の Shader Model 3.0 に相当
するのですが、Mobile GPU の多くはすでに Unified Shader です。
そのためあまり Vertex と Fragment Shader の機能差を意識する必要が
ありませんでした。
そんな中、Tegra2/3/4 は G70 ベースの GPU であり、Unified Shader 化する前の
制限が残っている珍しいケースとなっています。
コメントで Tegra の Fragment Shader は動的ループが使えないとの
指摘を頂いたので試してみました。
// (1) 動的ループ int loop= int( uniform_value ); for( int i= 0 ; i < loop ; i++ ){ ... }
↑ループ回数を動的に求めた場合、Vertex Shader は通りますが
Fragment Shader ではコンパイル時にエラーが発生します。
以前書いたように Uniform 配列の index アクセス ↓(2) も
Tegra の Fragment Shader ではエラーとなります。
どちらも Direct3D 9 世代の制限と考えられます。
// (2) Uniform 配列 uniform vec4 src_color[30]; ~ int index= int(tex_color.x); vec4 color= src_color[ index ]; // Tegra の Fragment Shader では Error
Tegra 4 でも同様なので、大幅に機能拡張されていても GPU のベースは
同じであることがわかります。
なお Tegra と同じように Discrete Type の Shader Unit を備える
Mai-400MP では動きました。
Vertex Shader Fragment Shader 動的Loop Uniform配列 動的Loop Uniform配列 ----------------------------------------------------------- Unified ◯ ◯ ◯ ◯ Mali-400MP ◯ ◯ ◯ ◯ Tegra2/3/4 ◯ ◯ ERROR ERROR
ただし Tegra でも動的分岐はできるので、実行時にループ回数が変動する
場合でも同等の処理を実現することは可能です。
// (3) Tegra向け 動的分岐によるループ for( int i= 0 ; i< 100 ; i++ ){ if( i >= Loop ){ break; } ~ 動的ループ相当 }
以下まとめ (いずれも Fragment Shader の場合)
コンパイル時にループ回数が定まらない場合はエラー。
// (4) ループ回数不定 -- Tegra で ERROR for( int i= start ; i< end ; i++ ){ ~ }
ループの範囲が決まっていればコンパイル可能。
// (5) 上限が決まってる場合 -- Tegra でも OK for( int i= 0 ; i< 100 ; i++ ){ if( i >= start && i < end ){ ~ 動的ループ相当 } }
おそらく下記のように展開されているものと考えられます。
i= 0; if( i >= start && i < end ){ ~ } i= 1; if( i >= start && i < end ){ ~ } ~ i= 99; if( i >= start && i < end ){ ~ }
Tegra K1 以降は ShaderModel 5.0 世代の GPU core になるので
このようなハードウエア的な制限はなくなるでしょう。
GPU 互換性など気軽に相談してください。
関連エントリ
・OpenGL ES 2.0 Adreno 330, Tegra 4 の GPU 速度
・OpenGL ES 2.0 で迷路シェーダー
・GLSL互換性