スポンサーサイト

■ スポンサー広告 Posted by ひぐま (Higmmer) on -------- at --:--:--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

XNA Game Studio Expressで遊んでいるうちに頭が痛くなってきた(1)

■ プログラム Posted by ひぐま (Higmmer) on 2006-09-07 at 23:35:37

ここんとこ国内外のゲームプログラミング界隈でXNAの話題が盛り上がっているようなので色々見て回っているのですが、早くも遊べるゲームを作りましたという人がちらほらいらっしゃるようで敬服させられっぱなしです。実際は以前からManaged DirextXを使っていた方が多いようですが、それでも始めて2~3日で遊べる状態のものを作り上げるというのはすごいと思います。

そんな自分はというと、完璧なものを作ろうとするあまり細かいところにばかり目が行ってしまって、種々の資料に当たったりXNAフォーラムを覗いたり試行錯誤したりの連続で遅々として作業が進みません。例を挙げるとリソースの作成はどのイベントハンドラで行うのが正しいのかとか、デバイス消失/破棄時の正しい処理方法とか、その際のリソースの再作成はどのように行うべきなのかとか……。主にC#(というか.NET)のGC機構とDirectX特有の仕様との折り合いをどうつけるかという問題なのですが。

リソースの作成については、ひげねこさんがこのように書かれています。

次は初期化コード。これはGraphicsDeviceのDeviceCreatedイベントハンドラの中に書きます。デバイスリセットはManaged プールのリソースを使えばいいのですが、マルチモニタ環境でウィンドウを他のモニタに移動した時には、デバイスの再構築が起きるので、それに対応するためです。

ひげねこにっき

「GraphicsDeviceの」とありますが正しくは「GraphicsComponentの」だと思うのですが(実際のコードもそうなってる)それはまぁいいとして、とにかくリソースの確保はDeviceCreatedイベントで行うのが正しいらしい(*)。但しResoucePool.Defaultで作成したリソースはDeviceLostで破棄してDeviceResetで再作成しないとダメですが、ResoucePool.Managedを使っている限りDeviceResetイベントはハンドルする必要はないというのが現時点での結論(間違っていたら教えて下さい)。

(*) XNAに付属の「Getting Started with XNA」にはDeviceResetイベントの中で行っているコード例が載っていますがこれはどうも誤りっぽい。実際、「SpaceWar Starter Kit」ではDeviceCreatedイベントを使っています。

で、ふと疑問に思ったのが作成時にResourcePoolを指定しないオブジェクトはどう扱うべきなのかと。例えばSpriteBatchのコンストラクタにはResourcePoolパラメータはありません。というかSpriteBatchって一体何者?? と思ってC++版のDirectXのドキュメントを当たってみるとID3DXSpriteインタフェースはDirect3D エクステンションに分類されていて(*)、VertexBufferやTextureといったIDirect3D系とは一線を画しています。ここから推測するにID3DXSpriteなどのD3DX系のオブジェクトは一連の描画命令(GPUコマンド)をまとめて発行するためのFacade的なものというか、単なるソフトウェアレイヤーなのかと理解したのですが、合ってるのかな?

(*) 他にもID3DXLineやID3DXMeshなどもここにあります。

ところが、よく分からないのはSpriteBatchはIDisposableインタフェースを実装しているということ。SpriteBatchがハードウェアリソースを使わないとしたら、Disposeは一体何を破棄しているのでしょうか? と思って.NET Reflectorを使って中を覗いてみたところ、Disposeから呼ばれるコードの中に次のような行がありました(簡略化してます)。

GraphicsDevice device1 = this.pCachedDevice; device1.Resources.ReleaseAllReferences((void*) this.pComPtr);

変数名から類推するに、要するに自分が持つCOMオブジェクト(ID3DXSprite)への参照を解放しているということでしょうか。よく考えたらもともとDirectXはCOMモデルの上に構築されているので、当たり前といえば当たり前か。とにかくDisposeを呼ばないとCOMの参照カウンタがゼロにならないので、いつまでもメモリ上に残ったままになると。……いや、SpriteBatchインスタンスへの参照がなくなった時点でGCの回収対象となるから、明示的にDisposeを呼ばなくてもファイナライザがDisposeするから問題ない??

うーん。考えれば考えるほど頭が痛くなる……。これがC++だったらデストラクタで必ずReleaseを書いておけばとりあえずOKなので何の問題もなくすっきりと理解できるんですが。とにかく、IDisposableを実装しているオブジェクトは使い終わったら必ずDisposeしといた方が無難ということか。で、それはそれで良いとしてじゃあデバイス消失/破棄のときはどういう処理をすべき(or すべきでない)なのでしょうか?? というわけで次回に続く。

トラックバック

この記事について書く(FC2ブログユーザー)
※言及リンクの無いトラックバックは無効です

PageTop▲

コメント

PageTop▲

コメントの投稿

 
 
 
 
 
 (後で編集・削除したいなら必須)
 
  

PageTop▲

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