今までテストに使用してきたプログラムが安定して動作しないため
Adreno 320 では速度の計測ができていませんでした。
LG Optimus G LGL21 を借りることができたのでもう一度テストしてみました。
・Mobile GPU ベンチ OpenGL ES 2.0
・CPU benchmark
・OpenGL ES Extension (Mobile GPU)
GPU bench の (1) 以外は 60fps に達するため数値が出ていません。
GPU 性能が上がったため、もはやこのテストは計測に向いていないことになります。
また Adreno 320 は OpenGL ES 3.0 世代の GPU ですが、
現在の OS から使う限り API は OpenGL ES 2.0 になります。
GPU 性能をまだ引き出せていない可能性があります。
テストプログラムのエラーの原因は特定のケースでシェーダーのコンパイルが
エラーになるもので、回避方法はわかったもののまだ詳しい条件が
特定できていません。
VFP test では HTC J HTL21 よりも良い結果が出ています。
(1) (2) (3) (4) (5) (6) iPad3 Touch5 EVO 3D iPad4 Butterfly OptimusG A5X A5 8660 A6X 8064 8064 C-A9 C-A9 Scorpion Swift Krait Krait ---------------------------------------------------------------- a:mat44 neon_AQ 4.784 5.979 2.879 1.204 1.919 1.354 b:mat44 neon_BQ 2.408 3.008 1.146 1.266 1.273 0.930 c:mat44 neon_AD 4.781 5.974 3.079 1.554 2.453 1.862 d:mat44 neon_BD 2.406 3.007 1.440 1.344 2.041 1.521 e:fadds A 4.010 5.013 3.460 2.882 3.791 2.831 f:fmuls A 4.010 5.012 4.361 2.953 3.671 2.793 g:fmacs A 4.012 5.011 4.034 5.763 7.334 5.599 h:vfma.f32 A ----- ----- ----- 5.765 3.725 2.743 i:vadd.f32 D A 4.111 5.136 3.493 2.877 3.706 2.724 j:vmul.f32 D A 4.110 5.136 3.502 2.950 3.667 2.767 k:vmla.f32 D A 4.512 5.650 3.638 2.951 7.557 5.462 l:vadd.f32 Q A 8.023 10.036 3.408 2.878 3.677 2.717 m:vmul.f32 Q A 8.022 10.028 3.427 2.952 3.647 2.741 n:vmla.f32 Q A 8.025 10.028 3.400 2.955 7.362 5.446 o:vfma.f32 D A ----- ----- ----- 2.494 3.676 2.709 p:fadds B 4.014 5.013 5.972 5.757 4.664 3.388 q:fmuls B 5.013 6.265 5.960 5.760 4.583 3.384 r:fmacs B 8.023 10.024 8.573 11.521 8.266 6.246 s:vfma.f32 B ----- ----- ----- 11.519 4.611 3.622 t:vadd.f32 D B 4.113 5.137 5.945 2.881 4.746 3.406 u:vmul.f32 D B 4.118 5.145 5.098 2.951 4.680 3.454 v:vmla.f32 D B 9.027 11.278 8.498 5.757 8.361 6.140 w:vadd.f32 Q B 8.021 10.023 5.950 2.879 4.702 3.481 x:vmul.f32 Q B 8.029 10.023 5.095 2.951 4.595 3.412 y:vmla.f32 Q B 9.026 11.277 8.497 5.762 8.464 6.249 z:vfma.f32 D B ----- ----- ----- 5.759 4.660 3.413 --------------------------------------------------------------- ↑数値は実行時間(秒) 数値が小さい方が速い (1)=Apple iPad 3 A5X ARM Cortex-A9 x2 1.0GHz (2)=Apple iPod touch 5 A5 ARM Cortex-A9 x2 0.8GHz (3)=HTC EVO 3D ISW12HT MSM8660 Scorpion x2 1.2GHz (4)=Apple iPad 4 A6X A6 (swift) x2 ?GHz (5)=HTC J butterfly HTL21 APQ8064 Krait x4 1.5GHz (6)=LG Optimus G LGL21 APQ8064 Krait x4 1.5GHz
Krait の FP 性能は Swift に並ぶ新 core であることがよくわかります。
前回のテスト時はクロックが上限まで上がっていなかった可能性があります。
HTC J butterfly が修理から戻ってきたらもう一度計測してみたいと思っています。
お久しぶりです。
Adreno320はかなり速いようですね。
しかしこちらはトラブルで苦しんでます。
症状は、トゥーンシェードの輪郭線を書くとテクスチャが黒くなってしまうというものです。
テクスチャを使っていない部分は正しく表示できています。
また輪郭も問題無く書けています。
しかしテクスチャだけが黒くなるのです。
同じ画面の、輪郭を書いていない部分のテクスチャは正しく表示されます。また、輪郭を書くのをやめると全部正しく表示されます。
輪郭は、同じvboを法線方向に引き延ばして書いています。
もしかするとvboを使い回すと干渉するのかもしれません。
しかし、輪郭は後から書いているのに、先に書いている部分がおかしくなるのは実に不可思議です。
内部の並列化でおかしくなっているのでしょうか。
chototsu さんお久しぶりです。
興味あるので、もし良ければこちらでも試してみたいと思います。
プログラムをいただくことは可能でしょうか。
修理に出していた HTL21 (APQ8064 Adreno 320) が復活しました。
テストプログラムのapkをメールフォームからお送りしました。
ソースはまだなのですが、今度最小限に削った物を作ってお送りします。
わざわざありがとうございます。
赤い輪郭だけ表示されていて、中が黒い状態なのを確認しました。
一番上のモデル以外はきちんと表示されているようです。
モーション無しで 50~60fps くらい。
メニュー、設定、輪郭線の太さをedge offにすると、表示されるはずです。輪郭線を書くとご覧のような状態になります。
現在市場にあるほとんどのGPUで動いているためレンダラのバグでは無いと思うのですが・・・。
ソースをメールでお送りしました。
お試し下さい。
まだlibを展開できておらずシェーダーとか描画周りを
見ていないのですが、AVD でも同じ症状が出ました。
GPU だけが原因とは言い切れないようです。
AVD : API Level 16 (ARM armeabi-v7a) "GPU emulation" Yes
HOST-GPU: Intel HD4000
テスト有り難うございます。
エミュレータでも再現しましたか。
エミュレータがOpenGL ES2.0に対応した直後に試したときはエミュレータでも動作したのを確認したのですが・・・。
ホストOSのGPUの違いでしょうか。
こちらはMacOSXでGPUはRadeon HD 6750Mです。
もう一度最新バージョンで確認してみます。
うーん、こちらの環境ではエミュレータでも動いていますね・・・。
ということは、Snapdragon S4 ProとIntel HD4000で駄目ということでしょうか。
rendering も java で行われているようですね。
render state とかシェーダーとか影響を与えている命令を
絞り込めればと思ったのですが、すぐには無理そうです。
とりあえず手持ちの環境でいろいろ試してみます。
物理エンジン以外は全部Javaです。
ですので、Windowsなどでも動きます。
レンダラのコードはOGLESShaderRenderer.javaにあります。
とりあえず再現出来る環境が無いとどうしようも無さそうなので購入を検討していますがまだまだ高いですね。
NEXUS4が日本で売られれば良いのですが。
御陰さまで解決しました。
まさかテクスチャユニットがシェーダに関連づけられているとは思いませんでした。
確かにその方がアーキテクチャとしては自然です。
nvidiaも私が持っているTegra2,3やGeForce 9600GTなどではグローバルな状態として扱われていますが、最新の物ではそうなっているのですね。
勉強になりました。
お久しぶりです。
またAdreno320でトラブってます。
今回のトラブルはFrameBufferのdepth bufferがおかしいというものです。
今うちでAndroidを利用したOculus Riftのようなデバイスを作っているのですが、
http://www.nicovideo.jp/watch/sm21353318
このシェーダがAdreno320だけで動きません。
具体的にはこのようなノイズが乗ってしまいます。
https://plus.google.com/105454326907346241584/posts/2nzfUHzNGF5
ノイズが乗るのは右目だけで左目用の部分は乗りません。
やっている事は、FrameBufferに一旦普通に描画し、それをテクスチャとして読み込んでレンズの歪みの変形を行っています。
なぜdepth bufferがおかしいと思うかといいますと、depth testをoffにすると描画されるからです。color bufferは問題無いようです。
ノイズですが、どうもOpenGLのcontextの外の画像を拾っているようです。理由は、notificationなどが出るとそれと思しきパターンがノイズに現れるからです。
depth bufferにはGL_DEPTH_COMPONENT16でrenderbufferを割り当てています。
(割り当てを外すとさらに描画が滅茶苦茶になりますので、間違い無く割り当てられていると思います)
何かヒントを頂けないでしょうか。
ステレオ(立体視)レンダリングでしょうか。
このケースではレンダリングの順番が問題になるかもしれません。
具体的にどのような順番でレンダリングしていますか?
・左右別のバッファを確保して、交互にレンダリング
・1つのバッファに右レンダリング、次に左レンダリング、など
以前の depth 値を再利用とかしてないでしょうか。
例えば
1. RenderTarget A に rendering
2. RenderTarget B に rendering
3. RenderTarget A の画像の上に上書きする
など。
TBL な GPU では以前のバッファ内容を保ったまま RenderTarget を頻繁に
切り替えると負荷が上がるので、その辺りで問題が生じるかもしれません。
また最近の GPU は、正しく clear 命令を発行しないとバッファがクリア
されない可能性があります。
試してませんが Adreno 320 では IMR に切り替えられるので、
結果が変わる可能性があります。こちらでも調べてみます。
あと 24bit depth でも同じ結果でしょうか。
アドバイス有り難うございます。
FrameBufferは左右別々に用意しています。
描画はこんな順序です。
1.左右のFrameBufferを個別に作成する。
2.左目用のFrameBufferにsceneを描画。
3.右目用のFrameBufferにsceneを描画。
4.左目用のFrameBufferをテクスチャとして取り出し、レンズの歪み変換をかけ画面に描画。
5.右目用のFrameBufferをテクスチャとして取り出し、レンズの歪み変換をかけ画面に描画。
レンズの歪みの変換はフラグメントシェーダで行っています。
FrameBufferは別個に用意していますからdepth値の再利用は行っていません。
glClearにGL_DEPTH_BUFFER_BITを立てて何度もクリアしていますが、color bufferのみクリアされ、depth bufferはノイズが乗ったままです。
FrameBufferの切り替えは正しく出来ているはずです。ノイズが乗るものの描画自体は間違っていません。
glGetErrorもチェックしていますがエラーは全くありません。
左目用の画面は正しく描画されますので、送っているコマンド自体は間違ってないと思うのですが・・・。
アプリはこちらで公開しています。
https://play.google.com/store/apps/details?id=info.projectkyoto.mms.tinyvr
cube map onにして背景を描画するとノイズの乗り方が分かりやすいです。
24bit depthは後で試してみます。
IMRの切り替えはどうすればいいのでしょうか?
FrameBuffer に attach した depth buffer も左右別でしょうか。
FrameBuffer に問題は出ていないでしょうか。
glCheckFramebufferStatus( GL_FRAMEBUFFER ) で確認できます。
左右逆順でレンダリングした場合はどうでしょう。
最後の合成時 (4.,5.) も depth buffer は有効でしょうか。
IMR への切り替えは下記の命令で行うようです。
実際に試したわけではないのでとりあえず引用だけ。
glHint( GL_BINNING_CONTROL_HINT_QCOM, GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM );
GL_BINNING_CONTROL_HINT_QCOM 等のシンボルは NDK ヘッダにはないですが、
khronos の最新の gl2ext.h や下記に記載されてます。
http://www.khronos.org/registry/gles/extensions/QCOM/QCOM_binning_control.txt
アドバイス有り難うございます。
24bit depthを試しました。
ノイズがさらに悪化しました。
> glCheckFramebufferStatus( GL_FRAMEBUFFER ) で確認できます。
FrameBufferを切り替える時に毎回行っています。
結果はすべてGL_FRAMEBUFFER_COMPLETEです。
> 左右逆順でレンダリングした場合はどうでしょう。
現象も逆になりました。左側にノイズが乗り、右側は正常でした。
ちなみに先にレンダリングした方は正常、後にレンダリングした方にノイズが乗ります。
> 最後の合成時 (4.,5.) も depth buffer は有効でしょうか。
有効になっていました。試しに無効にしましたが結果は同じでした。
ノイズが乗るのは2と3の段階です。理由は、ノイズにも4,5の歪みのフィルターがかかっている事、2,3で画面をべた塗りするとノイズも消える事です。
IMRへの切り替えはこれから試します。
IMRへの切り替えを行ってみました。
Javaで以下を実行しました。
GLES20.glHint(0x8FB0, 0x8FB3);
結果は変わりませんでした。
FrameBuffer に attach した depth buffer は左右別に確保したものでしょうか。
FrameBuffer と depth の解像度(サイズ)はいくつでしょう。
当たり前と思われるかもしれませんが、やはり 1つ1つ設定を
確認していくしか無いと思います。
例えば最初の描画終了時に DepthMask を FALSE にしたまま
2回目の Clear が呼ばれて depth buffer がクリアされてないとか。
Framebuffer/Renderbuffer (256×256 RGBA8888, depth16) を 2つ
作ってTexture に 3D レンダリングしてみましたが Adreno320
でも動いているようです。
(HTL21 Android 4.1.1 GLES 2.0)
IMR 切り替えはうまく行かないようですね。
余裕ができたら IMR/TBR の切り替えあたりは試したいと思ってます。
動きました。
まさにおっしゃるとおり、glDepthMaskが原因でした。
glClearの前にglDepthMaskを毎回呼ぶようにすると動きました。
大変助かりました。有り難うございます。
ただ腑に落ちないのは、前のバージョンでもPowerVR 540やTegra3では問題無く動いている事です。
もしglDepthMask(false)のままglClearを呼べば同じ問題が生じるはずなのですが・・・。
また、クリア出来ていないだけなら前の残像が残るだけで、砂嵐のようなちらつきは発生しないはずです。
前回のトラブルの原因になった、テクスチャユニットがシェーダに関連づけられているのと同じような仕様変更があったのでしょうか。
書き忘れましたがテスト機は
HTC J BUTTERFLY HTL 21(K)
です。
動いてよかったです。
いろいろと面白そうなアプリを作ってらっしゃるようですね。
未定義バッファの読み取りは動作が不定なので、
GPU やドライバによってはそのまま動作してしまうことが
あったのではないかと思います。
特に Framebuffer のクリアは GPU にとって違いが生じる部分で、
内部構造がそれぞれ異なっています。
depth ではフラグを立てるだけで値を書き込まないものも多いです。
今回の症状も HW 構造を考えるといろいろわかります。
タイル構造を視認できたので貴重な経験だったと思います。
OpenGL に関しては私自身あまりよく理解していない部分があります。
今更なのですが VAO の挙動を D3D と同じものだと
勘違いしていました。
仕様変更ではなく、私の理解が足りなかっただけだと思ってます。
シェーダーとオブジェクトのバインド周りも、
きちんと仕様を理解するために
ちょうどこれから解析してみようと考えていました。
有り難うございます。
元々Oculus Rift用に作り始めたのですがOcurus Riftが入手出来なかったためAndroidに移植しました。
シェーダーが相当重いので無理かと思ったのですがやってみるとそこそこ動いたので驚いています。最近のスマホは凄いですね。
尚、ハードとソフトはオープンソースで公開の予定です。
ところでまた質問で恐縮なのですが、うちのゲームエンジンを使って別の方が独自にOculus Rift用のシェーダを書かれました。
https://www.youtube.com/watch?v=dHz8uaDSd7I
その方からソースを頂いたのですが、うちのMacBook Proでは、Radeon HD 6750Mでは動きませんでした。Intel HD Graphics3000に切り替えると動きます。
原因を探ると以下の行が駄目でした。
float dy = cos(m_Dist*pos.x*m_Fov.x/180.0*PI+m_XShift/180.0*PI)*pos.y;
これをこう書き換えるとRadeonでも動きました。
float dy = cos((m_Dist*pos.x*m_Fov.x+m_XShift)/180.0*PI)*pos.y;
Radeon以外では上の式で問題無く動いています。
Radeonですと結果がNaNか何かになってしまうらしく、真っ黒になってしまいます。
無駄な演算があるのでオプティマイズがバグるのでしょうか。
MacBook ということは OpenGL 3.2 でしょうか。
GeForce では動作するのでしょうか。
入力値に何らかの不正な値が含まれている可能性はないでしょうか。
Intel HD3000 と違い RADEON HD6000 は OpenCL に対応しており、
IEEE754 に対してより厳密な実装となっている可能性があります。
以前の GPU はそこまで求められておらず、
描画が継続されているだけかもしれません。
また下の式よりも上の式の方が無駄とは認識しないので、
両者の違いは書いた通りの演算順番だと思います。
もちろんドライバを頻繁に更新していない場合は
シェーダーコンパイラのバグの可能性もあるかと思います。
やはり GLSL は GPU 毎にコンパイラも違うので、
D3D よりも考えられる問題範囲が広いのが難点だと思います。
ご回答有り難うございます。
他のGPUでは問題無く、私が知る限りトラブルがあったのはMacのRadeon HD 6750Mだけです。
m_と付く変数はJavaから渡しているuniformで、固定値です。Javaから渡していますのでそんな変な数値が入るとは考え難いのですが・・・。
それにしてもこのレベルでトラブルが発生してしまうと、GLSLのデバッグは本当に大変ですね。