2013年10月28日月曜日

Fatal signal 11 (SIGSEGV) ・・・ なんだよこれ!

何の音沙汰もなくアプリが落ちる。
あまつさえ端末が再起動し始める。

こんな場合、OpenGLのBuffer問題を考慮してみるのが有効かもしれません。
WebViewを使っている時も原因は同じようですが、こちらはクラスライブラリ内部の話なので解決策はよく分かりませんが。

先ず発生条件ですが、OSでは

・GB以前は無かった。ICS以降。ICSでも初めは問題なかった。

で、端末では

・シングルコアでは見た事が無い。どうもデュアルコア以降らしい。
・ainol Novo7Fire(CM10.1)だと起動後暫くすると発生。
・SAMSUNG GalaxyTab7.7Plusだと起動直後にフリーズ。

アプリでは

・別のスレッドでOpenGLを叩いている。
・例外では何も拾えない。

となります。何が推測できるかといいますと、

どうもGPUが参照中にアクセス保護しているメモリ領域に対して、アプリ側がコンフリクトを起こしている。

という事です。

OpenGLにデータを渡すためにnioのBufferクラスを使いますが、内部で持っているネイティブのメモリアクセスに対して何もしてなさそうです。
OpenGLに渡したBuuferへのアクセスを、OpenGLを叩いているスレッドだけに絞ると、このエラーはピタッと収まりました。

こんな事がありましたので、ご参考になれば。



2014/07/16 追記

少し具体的な説明です。
OpenGLは初期化したスレッドからのみ呼び出しが可能という仕様は知られていますが、
Javaで呼ぶ場合にデータを渡すために使ったBufferクラスのインスタンスへの書き込みも該当します。
OpenGLがBufferのメモリを覗いてせっせと描画している時に、別スレッドからBufferのメモリにアクセスするとコケるという具合です。

解決策としては、メインのスレッドではBufferに直接書き込まず、更新用の情報を別に用意します。
OpenGLを叩くスレッドで、描画する前に更新内容をBufferに適用すれば問題解決です。
面倒くさいんですが、マルチコアCPUの恩恵を受けるためには致し方ありません。








SAMSUNGてめ~w (初代ギャラタブとかのテクスチャが表示されない場合)

今更で需要は少ないかもしれませんが、古い機種も対応される方向けに・・・

SAMSUNGのAndroid2.2系端末、初代ギャラタブとかですね。この頃の機種はOpenGLのドライバに悲しいバグが色々あるのですが、検索で見つからず難儀した事を思い出したので軽く。

テクスチャ絡みで、テクスチャに割り当てるIDを払いだしてもらえるメソッドがあります。

結論:
そのメソッドを使ってはいけません。
(なんてメソッドだったか調べるの面倒くさいので、各自でよろしくです)

何故か:
負の値が払い出される事がある。その値をそのままテクスチャのバインドに使うと、そのIDに割り当てたテクスチャは呼び出せない。

gl.glBindTexture(GL11.GL_TEXTURE_2D, id);
GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bmp, 0);

これで id<0 だと、描画時にもう一回バインドしても何も描画されません。
ま、gl.glBindTexture()が負の値を受け付けないというか、0以下はバインド解除なんで当然なんですけれど。
ちなみに払い出しID値の法則性は不明。他のメーカーの端末とは異なり意味不明なバラバラな値。なんか擬似乱数っぽい感じでした。

解決策:
自分で適当なカウンタを用意して、それを勝手にIDとして使います。
IDはかぶらなければ、特に問題なかったです。OpenGLって、結構てきとうな作りですね。


assetに置いたファイルがMediaPlayerで再生できない → 解決


タッチのコントロールクラスが良い感じに片付いたので、そろそろほっぽっといたサウンド関連に着手しました。
で、MediaPlayerでassetに置いた.oggファイルを再生しようと思ったら、思いっきり躓きました。

普通にMediaPlayerを継承したクラス内で

AssetFileDescriptor afd = asset.openFd(filename);
try {
    setDataSource(afd.getFileDescriptor());
    prepare();
    start();
} catch (Exception e) {
    //
}

こんな感じで書けば音が鳴るんですが・・・というか鳴ってたんですが、しばらくするとprepare()で

java.io.IOException: Prepare failed.: status=0x1

となり、失敗するようになりました。
その前に数回は再生されていて、テスト端末を疑って再起動なども行いましたが変わらず。意味が分かりません。
このエラーの文言で検索しても不明でしたが、何とかなりました。
結論としてはsetDataSource()の所を

setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

こうしないとダメでした。なんでだ?
オフセットと長さを指定しないと例外って、AssetManager絡みの実装不具合っぽいですね。

とりあえず音関係クラスの実装が続きます・・・


--------その後


・・・一応、使える所まで完成しました。

ゲームに使う時のMediaPlayerとSoundPoolの切り分けが、使い勝手に直結するので難しかったです。
その内落ち着いたら、実装したものの解説でもしようかと思ってます。

何?このブログ

今Android向けにオリジナルゲームを作ってます。
それに先立ち、ゲームの基礎になるフレームワークっぽいのを作ってます。その過程でお役立ち情報が有れば書いていこうかと思い、ブログを開始した次第です。
(フレームワークなんて大それたものではなくて、ゲーム用コアライブラリって程度です)

やってる事は技術的に大した事ないのですが、元職業ゲームプログラマ的にポイントを絞って拘っていきたいと思います。


現時点での技術的な立ち位置は、

・描画はOpenGLのみで構成。Android独自のUIは基本使わない。独自のゲーム向けタッチパネルIU。

・OpenGLは現在1.1。後で2.0に移行予定。
 →実験してみたら、2.0は遅すぎて使い物にならなかったので移行は中止

・文字入力だけは、どうしようか悩み中。

・操作性を重視のため、フレームレートが稼げない3D関連は後回し。当初は2D描画が基本。
 …と言いつつ、3D描画も対応。最適化の方向性が2D向けになってます。

・リソース的に3Dモデルの用意が大変なので、やはりしばらくは2D描画が基本。その上で、3D的な演出を入れていく。

・エセ物理演算系を作成中。ビリアードとかのシミュレータ程度の処理で出来る演出を作成中。

・アプリは基本スタンドアロンでの動作。サーバサイドの処理は一切無し。
 サーバの維持コストを考えない企業・企画屋が多いですね。分かってない人達は恐ろしい。

・内部課金/月額課金はガン無視。広告付き無料と売り切り有料(+更新)のみ。
 自分はゲームで課金・月額にお金掛けたくありません。買いきり以外は興味ありませんので。

・Googleさんの「Google Play ゲーム」は様子見。実績とかは嫌いなので無視。
 データのセーブ場所としてライブラリ化予定。

・機種依存の根本的な排除。バージョンはAndroid2.2以降に対応。
 (やはり2.2捨てるかも…どうしよう)

・コードの記述性をなるべく落とさず、JavaのGCを走らせない構成。

・ゲーム上の内部データ処理に対して徹底した単位化。

・NDKはフレームの仕様が固まってから。後回し。

・オリジナルデザインののテキスト処理言語を使用。XMLとかは使わない。
 →ゲームの内部処理へ特化するため、再構成中。

・後日オンライン物も製作するが、分散型で各Android端末をサーバ化させる予定。


ゲーム自体のクオリティに関しては、最低でもPC-Engineの頃以上に保つのが目標です。
現在の開発ラインは、

・縦シュー的なプレイ感覚の平面シューティング
 → α版開発中、近日β公開
 → 有料版(+無料お試し版)は企画/リソース作業中

・横アクション。バシバシ攻撃できるアクションRPG系
 → 2種類企画中

・ネタ物の縦シュー、売名用無料版。パクリのパクリ。ついカッとなって作る予定。
 → 企画進行中


こんな感じです。
先ずはファーストリリースに向けて開発作業に専念しています。