dポイントプレゼントキャンペーン実施中!

お世話になっております。
さて、現在DirectX 9.0cを用いたゲームを製作しています。
このゲーム内で、いわゆるNowLoadingの画面を作成しているのですが、ここで気になることがあります。
ここでのNowLoadingの要件は、"描画とは別にスレッドを作成し、そのスレッドでロード処理を行う"ことです。
そこで、ドキュメント(古いDirectXの日本語ドキュメント)でマルチスレッドについて言及している箇所を検索してみると、CreateDeviceの引数にD3DCREATE_MULTITHREADEDを入れると、マルチスレッドに対応すると書いてあります。しかし、同時にパフォーマンスを下げるとの記述もあります。
しかし、D3DXCreateTextureFromFileなどD3DXCreate**系の関数が、LPDIRECT3DDEVICE9に対して参照だけを行い、BeginSceneなど描画に関する関数の挙動には(LPDIRECT3DDEVICE9に同時にアクセスしたとしても)、なんら影響がないならば、わざわざこのD3DCREATE_MULTITHREADEDフラグを使いたくありません。

そこで、サンプルを作成してみました。
http://briefcase.yahoo.co.jp/bc/multithreaddevic …
このサンプルは、上記の処理をD3DCREATE_MULTITHREADEDフラグをいれず、そのまま行っているもので、テクスチャを別スレッドで、ひたすらロードと、解放を行っています。これを実行した結果、特に問題ない(強制終了などしない)ように見えました。

この結果は、"たまたま動いている"だけなのでしょうか、それとも"必然的"なもので、別段行ってもいいものなのでしょうか?もしくは、状況による(SetRenderStateなどの使い方による、など)ものなのでしょうか?

ご教授よろしくお願いします。
環境は、DirectX9.0c (2008March)、XP sp3 になります。

A 回答 (1件)

>このサンプルは、上記の処理をD3DCREATE_MULTITHREADEDフラグをいれず、


>そのまま行っているもので、テクスチャを別スレッドで、ひたすらロードと、解放を行っています。
>これを実行した結果、特に問題ない(強制終了などしない)ように見えました。

D3DXCreateTextureFromFileとBeginScene他がたまたまメモリをお互いに干渉しない
ということでしょう。
もしg_pDevice->BeginScene();~g_pDevice->EndScene();
でテクスチャのロードが終わっていない段階で
テクスチャ(hoge.bmp)の読み込みを行えば落ちるでしょう。
まったく関係無さそうなDirectXのAPI同士(例えばBeginSceneとD3DXCreateTextureFromFile)
でもメモリを共有してる可能性があり
ランタイム等が変われば落ちる可能性はあります。
別のスレッドから呼ぶことは避けたほうが良いです。

マルチスレッドで問題になるのは異なる2つのスレッドで
メモリ対して読み込みと書き込み、或いは書き込みと書き込みが
同時に起こった時に整合性がとれなくなることです。
別にD3DCREATE_MULTITHREADEDを指定してなくても、
DirectXのAPIを呼び出す部分だけを専用のスレッドにすれば
他の部分はマルチスレッド化する事は可能です。
(プログラマとしてはD3DCREATE_MULTITHREADEDによって
どのような影響が出るかはMSDNで公開されている情報以外に
知る術は基本的にありません。とりあえずわかることは
D3DCREATE_MULTITHREADEDを指定すると
CriticalSectionを多様するようになる為
パフォーマンスに影響の可能性があると説明されています。
これ以上の事を知りたいならMSDNのフォーラムに質問すると良いかもしれません。)

ソースをみてスレッドの落とし方が気になりました。スレッドを安全に落とすためには
boolフラグ等を使ってスレッドで監視し、スレッド自ら終了させます。
それをメインスレッドでWaitForSingleObject(WaitForMultibleObject)を使い
スレッドのハンドルを監視しスレッドが終了したことを確認してから
CloseHandleを行った方が良いです。

"たまたま動いている"類のものはOSやDirectXのバージョン
が変わったときにアプリケーションごと落ちたりする事が
よくあります。(DirectXやOSの設計者が意図していない使われ方
をしている為です)

この回答への補足

sha-girlさん、回答をして下さった上に、ソースの不備まで指摘していただいて、ありがとうございます。

>"たまたま動いている"類のものはOSやDirectXのバージョン
>が変わったときにアプリケーションごと落ちたりする事が
>よくあります。
やはりこの方法では、危険ですか。。。
ゲームクリエイターをなさっているとのことなので、少し突っ込んだことを質問させて下さい。
今回のようなNowLoadingを実装するには、実際にはどのようにするのが理想的なのでしょうか?
自分で、思いつくものは下の二つです。
(1)ロードと、描画は別のスレッドで行うが、ロード中だけ、LPDIRECT3DDEVICE9を使用するときは自前でCriticalSectionを通すようにする。
(2)D3DCREATE_SOFTWARE_VERTEXPROCESSINGを使用してLPDIRECT3DDEVICE9を本来の描画用とは別にもう一つ作成し、それをロード中に描画に利用する。
  別スレッドで、本来の描画用に利用しているLPDIRECT3DDEVICE9でロード処理を行う。

(1)を利用すれば、DirectXが実際に何をやっているのかに関係なく、上手くは行くと思うのですが、あまり格好の良いものとは思えません。
(2)は一回試したのですが、これも偶然動いている可能性も捨てきれず悩んでいます。

補足日時:2008/08/02 00:02
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!