そろそろNexus7(2012)でもないだろうし、Intel Atom(x86)使用機種のような非ARM機が出てきたので、新たなAndroid端末として ASUS MeMO Pad7 ME572C を買ってきた。
今後はMIPS命令セット採用CPUなども含め、非ARMのAndroid端末も増えていくと思われるので、対応強化は進めておいた方が良いと思われる…のだけども。
試してみたところ ARM Emulation が非常に優秀でGLES2使用のゲームアプリ、特にndk使用が確実なタイトルやUnity製アプリなど確実にARMバイナリを含むタイトル*1がまともに動く。NVIDIA Tegra3のNexus7(2012)より軽快に動いてしまうものだから色々と複雑な気分だが、まあこの世界で2年の開きというのは大変に大きいので致し方ない。
そんな中、先日来自身で開発中のエンジンでGLES2周りの非互換部分(ただし回避可能)があったので、一応記録しておく。
問題点は、shaderのコンパイル後に行うステータスチェック。修正前は下記のようなコードだった。
GLint CGLShader::loadShader(GLenum type, const char * buf) { int shader = glCreateShader(type); GLint length; GLint compiled; glShaderSource(shader, 1, &buf, nullptr); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); length = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); if (length > 1) { // エラー処理 : } : }
上記のコードでは、glGetShaderiv()を GL_COMPILE_STATUS で呼んだ時の compiled を参照せず、エラー時には GL_INFO_LOG_LENGTH で length > 1 になることを期待していた。Windows上のGoogle ANGLEやNexus7(2012)のTegra3向けGL実装などではエラーがない場合その期待どおりに動くため問題は出なかったが、ME572CのPowerVR G6430向けGLES2実装では compiled != GL_FALSE であっても length > 1 である場合があるようで、shaderのコンパイルに成功しているにも関わらずエラーが発生したことになってしまっていた。
これは下記のようにエラーの有無は compiled のみで判断し、lengthはエラー発生時のメッセージの長さ、という扱いにすべきだった。OpenGL ES 2.0仕様を読み込んだわけではないので推測だが、仕様上エラーが無いときlengthの値は不定、ということなのだろう。
GLint CGLShader::loadShader(GLenum type, const char * buf) { int shader = glCreateShader(type); GLint length; GLint compiled; glShaderSource(shader, 1, &buf, nullptr); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (compiled == GL_FALSE) { length = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); if (length > 1) { // エラー処理 : } } : }
たしか似たような状況で動かない的な報告を他のアプリについてどこかで見かけた気もするので一応メモ。
*1:特に自分が開発に参加したタイトルについてはndk使用やUnity使用などの要件に間違いはないw