DXライブラリでスレッドを使ったファイルロード
Cation
2012/1/29に公開されたDXライブラリ3.07で非同期読み込みが公式にサポートされたので、特殊用途以外では以下の記事の内容はあんまし意味ないです...
……また自力で実装した機能が1ヶ月以内に公式サポートだよどうなってんのorz
DXライブラリ環境でマルチスレッド使って、裏でファイルをロードする
というのが今回の記事のテーマ。
NowLoading中にアニメーションとかしたいですよね。
自分で実装しようとした時に上記の具体的なコード例があんまし見つからなかった上に、あってもC言語ベタベタだったり、betterCなC++だったりするしで結構アレだった。
そして取り敢えずロード失敗とかしないのが出来たっぽいので、記事にしてみた。
まず前提として、DXライブラリはマルチスレッドに対応していない。
スレッドを立ててLoadGraphやらLoadSoundMem、DrawGraphやらを実行すると、データぶっ壊れた状態でロードされたり、描画されなかったりで色々と爆発する。
一応公式でマルチスレッドで死に「にくい」状態にする関数は存在するが、まぁ結構な確率でロード失敗とか使えたもんじゃない。
DXライブラリの関数を並列化は無理...なので
逆に言えば、DXライブラリ固有の動作"のみ"が並列になっていなければよい。(…と思う)
実際に試してみて気づいたのが、どうやらファイルをメモリ上にロードする系の機能(FileRead_openやFileRead_readなど)はマルチスレッドで何も問題がない。
※ 間違ってたらとても恥ずかしいのでツッコミください
という事で、メモリ上に読み込みだけを上記関数で行い、そのメモリ上のファイルからハンドルを作成するだけ。
ハンドル作成に要する時間は僅かなので、60FPSを維持するのも簡単だろうと思う。
実際のコード
動くのはこちら(https://github.com/joy1192/joylib)のDXLibs以下。Boost必須。まぁC++使っててゲーム作っているならBoost使っていると思うので(ry
※ 上記の開発環境はVS2010+Boost1.47.0+DXライブラリ
何してるかを簡単に書くと、
スレッド上で
// ファイルを格納するメモリ領域の確保 // 明示的new/delete面倒なのでvector使っとく std::vector<char> buffer( FileSize, 0 ); // 指定ファイルを開く int FileHandle = FileRead_open( "a.bmp" ) ; // ファイルを丸ごと確保済みメモリに読み込む FileRead_read( &buffer[0], buffer.size(), FileHandle ) ; // ファイルを閉じる FileRead_close( FileHandle ) ; // DXライブラリがマルチスレッドに対応してないので、クリティカルな部分を保護 { // このスコープ内は排他制御するようにする boost::mutex::scoped_lock lock(guard); // メモリ上に存在するファイルを使ってハンドルを作成する関数 // (画像の場合は)CreateGraphFromMemを使ってハンドルを作成 int Handle = CreateGraphFromMem( &buffer[0], buffer.size() ) ; // これでハンドル作れたので、このint値を好みな方法でどっかに格納したり、返せばOK } // ハンドル作ったらbufferの中身は要らないので、関数の終わりでvectorのデストラクタによって破棄
みたいな感じのを実装する。そうすると、普通に裏でロードができている。
描画は試してないのでアレだけれども、まぁメインスレッドで描画してファイルのロードだけ後ろでやればスムーズに動くし良いんじゃないですかね!
これ変だろとかバグあんぞとか指摘してくれると非常に喜びます。