Rakuten Card
Rakuten
Infoseek
Service
SDK [DirectX 9.0 SDK Update (Summer 2003)]、ランタイム [DirectX 9.0b] を使用しています。IDirect3DDevice9::SetRenderTarget メソッドの第2引数に NULL 以外の値を指定した場合、ヘルプには新しいレンダリング ターゲットの参照カウントはインクリメントされるとありますが、古いレンダリング ターゲットの参照カウントはデクリメントされるのでしょうか。
> IDirect3DDevice9::SetRenderTarget メソッドの第2引数に NULL 以外の値を指定した場合、ヘルプには新しいレンダリング ターゲットの参照カウントはインクリメントされるとありますが、古いレンダリング ターゲットの参照カウントはデクリメントされるのでしょうか。COM のセマンティクスに従うなら,DirectX Runtime が内部的に保持している参照が適切に処理されるだけなので,実際にデクリメントが起きるにせよ起きないにせよ呼び出し側で問題になることはない,というのが期待される動作です.そのようなセマンティクスの問題ではなく,純粋に Release メソッドの呼び出しにのみ興味があるのでしたら,IDirect3DSurface9 を実装した Proxy クラスを作って Relase メソッドの呼び出しを監視してみてはいかがでしょうか.
たとえば、次のプログラムを組んだ場合----------------------------------------------IDirect3DDevice9* pd3dDevice;IDirect3DSurface9* pNewSur;// 上記2つのインスタンスは既に存在しているとしてIDirect3DSurface9* pPrevSur; // s0pd3dDevice->GetRenderTarget(0, &pPrevSur); // s1pd3dDevice->SetRenderTarget(0, pNewSur); // s2pd3dDevice->SetRenderTarget(0, pPrevSur); // s3----------------------------------------------元々のレンダリングターゲットであったサーフェイスと pNewSur のそれぞれの参照カウントを、s0 直前の時点を基準にして相対値ゼロとします。SetRenderTarget メソッドで古いサーフェイスの参照カウントが減少しないのなら、s0 完了時点でそれぞれ相対値 0 と 0、s1 完了時点で +1 と 0、s2 完了時点で +1 と +1、s3 完了時点で +2 と +1 になります。一方、もし古いサーフェイスの参照カウントが減少するのであれば、s0 完了時点でそれぞれ相対値 0 と 0、s1 完了時点で +1 と 0、s2 完了時点で 0 と +1、s3 完了時点で +1 と 0 になります。プログラマがメソッドを使用して間接的に増やした参照カウントは、プログラマが責任を持って解放処理をしなければなりません。ところが、上記の思考実験によると、SetRenderTarget メソッドの内部実装よって、解放処理の必要な回数が変わってくると思いました。自分の中では、なぜヘルプに参照カウントが減少するのかどうかが明記されていないのか不思議なので、> 実際にデクリメントが起きるにせよ起きないにせよ呼び出し側で問題になることはない,というのが期待される動作ですこの「問題になることはない」というのが、なかなか納得できない状態なのです。本当に全く問題ないのでしょうか。問題ないとして、結局、参照カウントを相対値ゼロに戻すには何回解放処理をすればよいのか、ヘルプに明記されていないのにそう言えるのか理由を教えて頂けないでしょうか。やや混乱しています。また、そもそも上記の思考実験は正しくないのでしょうか。> IDirect3DSurface9 を実装した Proxy クラスを作って Relase メソッドの呼び出しを監視してみてはいかがでしょうかそうは思いましたが、以前別の COM 関係の検証で似たような実験をし、大変苦労した、というか面倒な思いをしたので、だれか知っていればその知識を分けて欲しかっただけです。だれも知らないのなら、自分で実験することにします。
> 自分の中では、なぜヘルプに参照カウントが減少するのかどうかが明記されていないのか不思議なので、>> > 実際にデクリメントが起きるにせよ起きないにせよ呼び出し側で問題になることはない,というのが期待される動作です> > この「問題になることはない」というのが、なかなか納得できない状態なのです。本当に全く問題ないのでしょうか。問題ないとして、結局、参照カウントを相対値ゼロに戻すには何回解放処理をすればよいのか、ヘルプに明記されていないのにそう言えるのか理由を教えて頂けないでしょうか。やや混乱しています。上の例であれば,s1 の前後でライブラリ利用者は pPrevSur の参照を 1 つ得ています.s0 直前から s3 直後までに,ライブラリ利用者はトータルで pPrevSur の参照を 1 つ得ました.よってライブラリ利用者は pPrevSur への関心が無くなった段階で pPrevSur->Release() を 1 度だけ呼び出す責任があります.> また、そもそも上記の思考実験は正しくないのでしょうか。参照カウントがどうなるか分からない,というところまでは正しいと思います.ライブラリ内部での参照カウントの扱いはライブラリ内部での参照関係に依存するわけで,interface と寿命管理の規約しか定めない COM では内部実装がどうなるかは予言できないでしょう.しかし,「解放処理の必要な回数が変わってくる」という判断には異議があります.・GetRenderTarget が隠れた AddRef を呼び出すこと (これは引数として COM Interface をやりとりする際の規約です)・s0 直前から s3 直後までに他の AddRef が存在しないことこれよりライブラリ利用者はライブラリの内部実装にかかわらず pPrevSur->Release() を 1 度だけ呼び出すことが求められます.もちろんライブラリごとのセマンティクスが存在して,COM の規約以外に従うべき条件があるかもしれません.しかしそのようなセマンティクスは COM の規約と矛盾しないことが求められます.例えば,ライブラリが内部的に保持する参照は,「ライブラリに解放させるべき」です.実際 IDirect3DDevice9::SetTexture( 0, ptr ); でライブラリ内部に発生した参照を解消するには IDirect3DDevice9::SetTexture( 0, NULL ); を使う,というのが DirectX のセマンティクスです.> そうは思いましたが、以前別の COM 関係の検証で似たような実験をし、大変苦労した、というか面倒な思いをしたので、だれか知っていればその知識を分けて欲しかっただけです。だれも知らないのなら、自分で実験することにします。COM という規約レベルの話としては『Essential COM』が参考になります.http://www.amazon.co.jp/exec/obidos/ASIN/4756130666設計論としては『Effective COM』もお奨めです.http://www.amazon.co.jp/exec/obidos/ASIN/4756131662
とても分かりやすい説明、ありがとうございました。納得できました。ヘルプの IDirect3DDevice9::SetRenderTarget メソッドの説明に、新しいレンダリング ターゲットの参照カウントがどうなるのかについて書かれていたので、どうもぞのことを意識し過ぎたようです。入れ替わる古いサーフェイスどころか、そもそも、新しいサーフェイスの参照カウントの事すらプログラマには関係ないのですね。古い方も新しい方も、どちらもライブラリ側で参照カウントの増減処理が行われているので、最後(かどうかは分からないが)にその参照カウントを以前の状態に戻すのはプログラマではなくライブラリの責任。ただし、IDirect3DDevice9::SetTexture メソッドの様に、直接解放するのはライブラリ側であっても、その処理をプログラマ側で明示的に誘発しなければならないことがヘルプに書かれている場合は、結局はプログラマ側の責任(そういう大事なことはテクスチャ リソースではなく、ちゃんと IDirect3DDevice9::SetTexture メソッドの説明ページに書け、とは思うけど)。また、ライブラリが参照カウントを増やすのが、プログラマ側に参照のコピーを渡すためであれば(GetRenderTarget など)、その参照カウントを減らすのはプログラマの責任。ということなんですね。
> ただし、IDirect3DDevice9::SetTexture メソッドの様に、直接解放するのはライブラリ側であっても、その処理をプログラマ側で明示的に誘発しなければならないことがヘルプに書かれている場合は、結局はプログラマ側の責任(そういう大事なことはテクスチャ リソースではなく、ちゃんと IDirect3DDevice9::SetTexture メソッドの説明ページに書け、とは思うけど)。確かにドキュメントはもっと詳しく書いて欲しいというのは同意です.余談ですがこれに関して以下のスレッドが面白い内容となっています..NET における IDisposable を用いたリソースの寿命管理に関するスレッドで,IDisposable という (interface による) 契約の重要性と,ライブラリ依存のセマンティクスはヘルプからしか知ることが出来ないという問題提起 (by 吉松さん) が議論の中心となっています.非常に長く複雑な議論が続いたため一部で伝説となっているスレッドですが,時間が十分にあるときに暇つぶしにでもどうぞ.http://www.gdncom.jp/general/bbs/ShowPost.aspx?PostID=4718上記スレッドでは結局万能な解決策には至りませんでしたが,私がフレームワークの設計を行う際今でもしばしば参考にすることがあります.