[この記事は Games Developer Advocate の Shanee Nishry による Android Developers Blog の記事 "Game Performance: Layout Qualifiers" を元に、萩倉が翻訳・加筆したものです。詳しくは元記事をご覧ください。]

今日は OpenGL Shading Language (GLSL)を利用してゲームのパフォーマンスを最適化し、ワークフローを簡素化するベスト プラク ティスについてお伝えします。Layout Qualifiers は特にコードの確定性を高め、作業者の負荷を減らしてパフォーマンスを高めます。

簡単な頂点シェーダーに変更を加えてみましょう。

位置座標とテクスチャ座標を取得し、頂点の位置を変換し、フラグメント シェーダーにデータを渡す、基本的な頂点シェーダーの例を次に示します。
attribute vec4 vertexPosition;
attribute vec2 vertexUV;

uniform mat4 matWorldViewProjection;

varying vec2 outTexCoord;
void main()
{
  outTexCoord = vertexUV;
  gl_Position = matWorldViewProjection * vertexPosition;
}

頂点属性インデックス

画面にメッシュを描画するには、頂点バッファを作成し、頂点データ(ここでは位置座標、テクスチャ座標など)を登録する必要があります。

サンプル シェーダーで頂点データを次のように記述します。
struct Vertex
{
  Vector4 Position;
  Vector2 TexCoords;
};
これに従い、頂点シェーダーの属性を次のように定義します。
attribute vec4 vertexPosition;
attribute vec2  vertexUV;
glGetAttribLocation へのコールによって指定された名前の属性の処理が行われ、頂点データがシェーダー属性と関連づけられます。すると属性フォーマットが glVertexAttribPointer へのコールとともに記述されます。
GLint handleVertexPos = glGetAttribLocation( myShaderProgram, "vertexPosition" );
glVertexAttribPointer( handleVertexPos, 4, GL_FLOAT, GL_FALSE, 0, 0 );
GLint handleVertexUV = glGetAttribLocation( myShaderProgram, "vertexUV" );
glVertexAttribPointer( handleVertexUV, 2, GL_FLOAT, GL_FALSE, 0, 0 );
しかし、vertexPosition 属性をもつ複数のシェーダーがある場合、各シェーダーの glGetAttribLocation を呼び出すのはパフォーマンスを無駄にし、ゲームの読み込み時間が長くなります。

Layout Qualifiers を利用すると、頂点シェーダー属性の宣言を次のように変更できます。
layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexUV;
またそのためには、使用するシェーダーが GL ES 3.1 に対応していることをシェーダー コンパイラーに伝える必要があります。

以下のバージョン宣言を追加します。
#version 300 es
例示のシェーダーがどのようになるかを見てみましょう。変更点を太字で示します。
#version 300 es

layout(location = 0) in vec4 vertexPosition;
layout(location = 1) in vec2 vertexUV;

uniform mat4 matWorldViewProjection;
out vec2 outTexCoord;
void main()
{
  outTexCoord = vertexUV;
  gl_Position = matWorldViewProjection * vertexPosition;
}
OutTexCoord が varying 変数から out 変数に変わっていることもご確認ください。Varying キーワードはバージョン 300 es から動作が保証されなくなったため、シェーダーを機能させるには変更が必要です。

頂点属性の修飾子と #version 300 es は OpenGL ES 3.0 以降でサポートされています。デスクトップ版は OpenGL 3.3 でサポートされ、#version 330 が使用されています。

ここで位置属性が常に 0 で、テクスチャ座標が 1 になるとわかったら、glGetAttribLocationを使わずに次のようにシェーダー
フォーマットをバインドできます。
const int ATTRIB_POS = 0;
const int ATTRIB_UV   = 1;

glVertexAttribPointer( ATTRIB_POS, 4, GL_FLOAT, GL_FALSE, 0, 0 );
glVertexAttribPointer( ATTRIB_UV, 2, GL_FLOAT, GL_FALSE, 0, 0 );
この簡単な変更でパイプラインを明確にし、コードをシンプルにして、起動の際の負荷を削減できます。

Android でのパフォーマンスの詳細については、Android Performance Patterns の動画シリーズをご覧ください。

Posted by Takeshi Hagikura - Developer Relations Team