はじめに
これまでにも何度か紹介してきましたが、クリアコードではGecko(Firefox)を組み込み機器向けに移植する取り組みを行っています。
当プロジェクトでは移植コストを少しでも低減するために、Firefoxの延長サポート版(ESR)のみを対象としています。これまではESR45やESR52をベースにハードウェアアクセラレーションに対応させるための作業を行ってきました。 現在はESR60に対応し、そのバグを修正する作業を進めています。
この作業に関連するOpenGL ESのデバッグをする必要が生じたのでその方法を解説します。 今回のデバッグにはapitraceというOpenGLに関するAPIの呼び出しを取得できるツールを使いました。このツールを元に今回のデバッグ方法を解説します。
OpenGLのAPIの呼び出しをトレースするには
apitraceを用いてOpenGLのAPIの呼び出しをトレースするには、以下のようにして行います。
$ apitrace trace --api=egl --output=/tmp/dump.trace [トレースするプログラム]
例えば、FirefoxのOpenGL ESのAPIの呼び出しのトレースを取得するには以下のようにすると取得できます。
$ apitrace trace --api=egl --output=/tmp/dump.trace firefox
OpenGLのAPIの呼び出しのダンブを解析するには
apitraceには採取したダンプを解析する機能もあります。
$ apitrace dump /tmp/dump.trace
とすると、OpenGL ESのAPIの呼び出しを記録したダンプの解析を行えます。 例えば、Firefoxを用いてOpenGL ESのAPIの呼び出し結果を取得し、その結果を解析すると以下のような出力が得られます。
// process.name = "/usr/lib/firefox/firefox"
0 eglGetDisplay(display_id = 0xb6921120) = 0x1
1 eglInitialize(dpy = 0x1, major = NULL, minor = NULL) = EGL_TRUE
9 eglChooseConfig(dpy = 0x1, attrib_list = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE}, configs = {0x2, 0x1, 0x3}, config_size = 64, num_config = &3) = EGL_TRUE
14 eglCreateWindowSurface(dpy = 0x1, config = 0x2, win = 0x9d1e7af0, attrib_list = {}) = 0x9ce7d000
15 eglBindAPI(api = EGL_OPENGL_ES_API) = EGL_TRUE
16 eglCreateContext(dpy = 0x1, config = 0x2, share_context = NULL, attrib_list = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE}) = 0x9d1638b0
140 eglGetCurrentContext() = NULL
141 eglMakeCurrent(dpy = 0x1, draw = 0x9ce7d000, read = 0x9ce7d000, ctx = 0x9d1638b0) = EGL_TRUE
# ...
27660 glDeleteProgram(program = 1050015)
27661 eglGetCurrentContext() = 0x9d1638b0
27662 glDeleteProgram(program = 840012)
27663 glBindFramebuffer(target = GL_FRAMEBUFFER, framebuffer = 0)
27664 glDeleteBuffers(n = 1, buffers = &140002)
27665 glDeleteBuffers(n = 1, buffers = &70001)
27666 eglGetCurrentContext() = 0x9d1638b0
27667 eglGetCurrentContext() = 0x9d1638b0
27668 eglDestroyContext(dpy = 0x1, ctx = 0x9d1638b0) = EGL_TRUE
27669 eglMakeCurrent(dpy = 0x1, draw = NULL, read = NULL, ctx = NULL) = EGL_TRUE
27670 eglDestroySurface(dpy = 0x1, surface = 0x9ce7d000) = EGL_TRUE
この結果を見ると、FirefoxがEGLを使用する際には、EGLDisplayを取得し、EGLのコンフィグを元にしてEGL WindowSurfaceを作成してからようやくEGLのコンテキストが動き出していることが記録されていることがわかります。
反対に、終了時には動いているEGLのプログラムを片付けてから現在のEGLコンテキストの破棄、EGL WindowSurfaceの破棄を行なっていることが読み取れます。
apitraceを用いるとOpenGL ESのAPIの呼び出しが成功しているのか、失敗しているのかがある程度判別できます。
14 eglCreateWindowSurface(dpy = 0x1, config = 0x2, win = 0x9d1e7af0, attrib_list = {}) = 0x9ce7d000
の箇所を例にとると、上記の呼び出しでは正常にWindowSurfaceが作成されていることが読み取れますが、
14 eglCreateWindowSurface(dpy = 0x1, config = 0x2, win = NULL, attrib_list = {}) // incomplete
となってしまっている場合は eglCreateWindowSurface
の呼び出し直後に正常の動作ではない状態になっています。
実際に、このような状況になってしまった時はfirefoxがSEGVしました。
まとめ
FirefoxのOpenGL ESのAPIの呼び出しのダンプを取ることを例にしてapitraceの基本的な使用方法を解説しました。 OpenGL (ES)はハードウェアが絡むためログを仕込むような伝統的なデバッグ手法によるデバッグが難しく、このようなツールに頼ることで別の視点からの情報が得られることが分かりました。 グラフィックに関するデバッグで困っている場合はこのようなツールの助けを借りることも検討してみてはいかかでしょうか。