10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Android向けOpenGLゲーム開発におけるマルチスレッドパターン

最近、私が取り組んでいたAndroidアプリ開発で、OpenGL&JNI&マルチスレッドを含む開発ではまっていました。
ようやく解決できたので、それについてご報告です。




OpenGLを利用したリアルタイムアプリケーションで考慮すべきこと


AndroidでOpenGLを使ったアプリを開発する場合、GLSurfaceViewを使います。
GLSurfaceViewは独自のレンダリング用スレッドGLThreadを起動するので、 自動的に2つのスレッドが動作する事になります(UIスレッドとGLスレッド)。
さらに、効率的な処理を行おうとすれば、ゲームループ用にゲームスレッドを使用する事になります。
この時点で3つのスレッドが存在します:


・UIスレッド(AndroidのActivityが動作するスレッド)
・GLスレッド(Rendererが動作するスレッド)
・ゲームスレッド(ゲームループが動作するスレッド)


さらに意識すべきことは:


・どのタイミングでJava、native(JNI)のリソースを確保し、解放すればよいか
・UIイベントをどのようにゲームスレッドに伝えるか

という点になります。
これらをうまく扱わないと、動作速度の低下、デッドロックの発生、あるいは何の音沙汰も無くアプリが停止するという悲劇が待っています。特に、何の音沙汰も無く(例外ログやメッセージ表示も無く)いきなりアプリが消えてしまうのが非常に厄介です。
私もこのような不具合に見舞われたのですが、調査、試行錯誤の結果次節のパターンにたどり着きました。

OpenGL描画を行う場合のマルチスレッドパターン

1. リソース確保・解放のタイミング


リソース確保・解放のタイミングはActivityのライフサイクル、およびGLSurfaceView.Rendererのライフサイクルに関連します。
まず、Activityのライフサイクルを見ましょう。Activityは以下のライフサイクルを持ちます:

参考:http://developer.android.com/intl/ja/reference/android/app/Activity.html

次にGLSurfaceView.Rendererのライフサイクルを見てみましょう。
GLSurfaceView.Rendererは以下の3つのメソッドを持ちます:

・onSurfaceCreated(): OpenGLレンダリングコンテキストが準備できたタイミングを示す。
・onSurfaceChanged(): OpenGLサーフェスのサイズが変更されたことを示す。
・onDrawFrame(): 描画のタイミングを示す。


上記Activity、およびGLSurfaceView.Rendererのライフサイクルを利用して実装を行うわけですが、この中で私が意識するのはActivity.onCreate(), Activity.onResume(), Activity.onPause(), Activity.onDestroy()、ならびにRenderer.onSurfaceCreated(), Renderer.onSurfaceChanged(), Renderer.onDrawFrame()です。
これらの、私の場合の使い方を以下に示します:

Activity側:
・Activity.onCreate()
  1. OpenGLに依存しないリソースの確保
  2. GLSurfaceView継承クラスのインスタンス生成~初期化
・Activity.onResume()
  1. ゲームスレッドの生成~実行(Thread.start())
・Activity.onPause()
  1. ゲームスレッドの停止(Thread.interrupt(), Thread.join())~破棄
  2. JNI側(nativeコード)の終了ルーチンの実行(nativeメソッドコール)
  3. OpenGLに依存するリソースの破棄(※1)
・Activity.onDestroy()
  1. OpenGLに依存しないリソースの破棄
(※1) onPause()の時点で既にOpenGLコンテキストは無効となっていますので、OpenGL上のオブジェクト(テクスチャなど)の破棄は行いません。ここではOpenGLを利用するオブジェクトなどのリソースを破棄することを行います。

GLSurfaceView側:
・GLSurfaceView.Renderer.onSurfaceCreated()
  1. OpenGLに依存するリソースの確保(テクスチャなど)
  2. JNI側(nativeコード)の初期化ルーチンの実行(nativeメソッドコール)
・GLSurfaceView.Renderer.onSurfaceChanged()
  1. ビューポートの設定(glViewport()をコール)
・GLSurfaceView.Renderer.onDrawFrame()
  1. レンダリング

赤字で示した部分がここでの重要ポイントとなります。
onPause()はOpenGLコンテキストが無効になって最初にコールされるメソッドなので、リソース破棄の処理を行います。ここで、赤字に示しているように、まずはゲームスレッドを停止しましょう。ゲームスレッドを停止する前にJNIの終了ルーチンをコールしてしまうと、ゲームスレッドからnative側の無効になったポインタへのアクセスが発生する可能性があり、何のメッセージも無くアプリが消えてしまう状況が起こりえます。(私はこれに悩まされました)
naitive側にグローバルなフラグでも用意すれば良いと思われるかもしれませんが、そもそも無効なポインタへのアクセスの可能性を排除すれば問題は消えます。
また、naitive側のグローバル変数はあまり信用できません。共有ライブラリのグローバル変数は、ライブラリがロードされた時点でもちろん初期化されます。しかし、Androidのプロセス管理は、「アプリケーションが起動すると既存の共有ライブラリがメモリ上にあれば再利用し、なければロードする」という動作をするので、グローバル変数が初期化されたかどうかは分からないのです。なので、明示的に初期化して使う必要があります。

2. UIイベントの処理


描画処理がメインのOpenGLアプリケーションですが、UIイベントの処理は欠かせません。
ここでは、UIイベントをどのようにゲームスレッドに伝えるかを説明します。

単純に考えれば、Activityのイベントメソッド(onTouchDownなど)がコールされるたび、ゲームスレッドクラスのsynchronizedイベントメソッドをコールする、という方法が考えられます。しかしこの方法は上手くいきません。
理由は不明ですが、デッドロックが起きます。(UIスレッドは優先度が低いのかもしれません)
これに対処するため、イベントキューを自作し、このキューをsynchronizedでロックして、イベントを伝えます。
詳しい方法はこのサイトを参考にしてください。(私もこのサイトにお世話になりました)

3. GLスレッド、ゲームスレッドの通信


この節は指針程度の内容ですがご勘弁を。
ゲームスレッドはゲーム状態の更新を行い、GLスレッドは描画を担当します。このとき、GLスレッドはゲーム状態を表すオブジェクトを参照して描画を行います。つまりゲーム状態を表すオブジェクトが同期(synchronize)される必要があるということです。ここで重要なのは、どれが同期が必要なオブジェクトなのかを精査し、synchronizeでロックされる範囲を極力小さくすることです。これをせず、大雑把に更新処理メソッド単位や描画処理メソッド単位でsynchronizeしてしまうと、これらメソッドが同期化されてしまい、せっかくゲームスレッドを作った意味がありません。なるべく小さな範囲を同期化しましょう。処理速度が向上します。


以上、私なりのOpenGL使用時のマルチスレッドパターンをご紹介しました。

にほんブログ村 IT技術ブログ ゲーム開発へ
応援クリックありがとうございます!
Secret

アクセスカウンター

プロフィール

青柳篤志

Author:青柳篤志
CreoSproutソフトウェア研究部へようこそ!
Android、Windows用ゲーム等公開しています。
Check



Add to Google

カテゴリー

最近の記事

最近のコメント

月別アーカイブ

Androidアプリ

レンダリングアルゴリズム完全更新!「CreamSplash」公開中!(2011/12/6更新)
(for Android 2.2 以上) 300円(税込み)
https://blog-imgs-15-origin.fc2.com/a/h/i/ahirujigen/app_icon_r02_100x100.png

シンプルパズルで女の子の水着イラストを見よう!「PanelFlip 2 Free」公開中!(2011/8/1公開)
(for Android 2.2 以上) 無料
app_icon_100x100.jpg

Match 3 タイプのパズルゲーム!「LED Match」公開中!(2011/8/28公開)
(for Android 2.2 以上) 無料
app_icon_100x100.jpg

シンプルパズルで女の子の水着イラストを見よう!「PanelFlip Free」公開中!(2011/7/22公開)
(for Android 2.2 以上) 無料
app_icon_100x100.jpg

Windowsアプリ

タワーディフェンス系リアルタイム戦術ゲーム「小戦術」販売中!(2011/5/6発売)
(for WindowsPC) 945円(税込み)

リアル液滴シミュレータ「ぶっかけ職人」販売中!
(for WindowsPC)

[まだまだ人気!]
数字と萌えの脳トレゲーム「カズアワセ2」販売中!
(for WindowsPC) 830円(税込み)

[まだまだ人気!]
「カズアワセ2」追加ステージパック「カズアワセ2.1」販売中!
(for WindowsPC) 105円(税込み)

インタラクティブイラスト集「MioPlay」販売中!
(for WindowsPC) 735円→315円(税込み)

ZIP圧縮連番動画結合ツール「動画即結たん1.1.0」(どうがそっけつたん)ただいま販売中!
(for WindowsPC) 630円 → 315円(税込み

twitter

pixiv

ブログ内検索

RSSフィード

リンク

リンク2




アクセスランキング





にほんブログ村 IT技術ブログ ゲーム開発へ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。