日別アーカイブ: 2013年8月30日

Adreno 320 の OpenGL ES 3.0 と Uniform Block

前回 Nexus 7 の Adreno 320 で OpenGL ES 3.0 のシェーダーが正しく動作しないと
書いたのですが、条件が絞れてきました。

UniformBlock の変数を直接演算に用いると Shader Compiler の
glLinkProgram() で Internal Error が発生するか直後にクラッシュします。

#version 300 es

// GLSL: VertexShader

precision highp float;

uniform SceneBlock {
    mat4   PView;
    mat4   ViewMatrix;
};

in vec3 POSITION;
in vec3 NORMAL;
in vec2 TEXCOORD;

out vec3 onormal;
out vec2 otexcoord;

void main()
{
    vec4 opos= vec4( POSITION.xyz, 1.0 ) * PView; // ← ここ

    opos.z= 2.0 * opos.z - opos.w;
    gl_Position= opos;
    onormal= vec3( 0.0, 0.0, -1.0 );
    otexcoord= TEXCOORD.xy;
}

下記のように、Uniform Block 内の変数を一旦ローカル変数にコピーすると
問題なく動くようになります。

void main()
{
    mat4 pv= PView;  // Uniform Block の変数をローカルにコピー
    vec4 opos= vec4( POSITION.xyz,1.0 ) * pv;

    opos.z= 2.0 * opos.z - opos.w;
    gl_Position= opos;
    onormal= vec3( 0.0, 0.0, -1.0 );
    otexcoord= TEXCOORD.xy;
}

Fragment Shader も同じです。

OpenGL ES 2.0 では Uniform Block が無いので問題ありません。

OpenGL ES 3.0 でも Uniform Block を使わない ( default Uniform Block だけ使う)
場合も問題ありませんでした。

Adreno 320 以外ではどちらのコードも動きます。
Mali-T604 実機, Adreno SDK の OpenGL ES 3.0 Emulator,
Mali Developer Tools の OpenGL ES 3.0 Emulator いずれも問題ありませんでした。

症状を確認した本体

・Nexus 7 (2013)
・Android 4.3 JSS15Q

GL_VERSION: OpenGL ES 3.0 V@14.0 AU@  (CL@)
GL_RENDERER: Adreno (TM) 320
GL_VENDOR: Qualcomm
GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 3.00

購入直後一度システムソフトウエアの更新があり、GL_VERSION の内容が
置き換わっています。上記は更新後です。
更新後も同じ症状が出ています。

回避方法がわかったので、とりあえず Adreno 320 でも OpenGL ES 3.0 用
シェーダーの動作確認ができました。

他に Intel HD 4000 (9.18.10.3165) でも Uniform Block で問題が出ています。
Uniform Block 内で mat3x4 の配列を宣言すると、index の計算を間違えるようです。
(layout std140 指定済み)
すべて vec4 宣言し、自分で matrix に組み立てることで回避できます。

関連エントリ
Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)