3

D3DImage を使用して、Direct3D を使用してレンダリングされた画像を表示しています。Direct3D レンダリングは独自のスレッドで実行する必要がありますが、GUI スレッドは必要に応じてサーフェスを取得し、D3DImage を使用して画面に配置します。

最初は単一の D3D レンダー ターゲットを使用してこれを実行しようとしましたが、ロックが設定されていても深刻なティアリングが発生しました。つまり、WPF がサーフェスをフロント バッファーにコピーするときに、レンダリング スレッドがサーフェスを上書きしていました。WPF は、いつデータをコピーするかについて非常に予測できないようです (つまり、ドキュメントが示唆するように、D3DImage.Unlock() または次の D3DImage.Lock() ではありません)。

今私がやっていることは、2 つのレンダー ターゲットがあり、WPF がフレームを表示するたびに、レンダリング スレッドにそのターゲットを交換するように要求することです。だから私は常にWPFが使用していないターゲットにレンダリングしています。

これは、ウィンドウのグラフィカルな更新ごとに、次のようなことを行うことを意味します

m_d3dImage.Lock();
m_d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, m_d3dRenderer.OutputSurface);
m_d3dImage.Unlock();
m_d3dRenderer.SwapSurfaces();

ここで、OutputSurface は、現在レンダリングしていない D3D レンダー ターゲットを指す IntPtr であり、SwapSurfaces は 2 つのサーフェス ポインターを交換し、IDirect3DDevice9::SetRenderTarget を次にレンダリングするために使用するもので呼び出すだけです。

編集: 要求に応じて、SwapSurfaces() のコードは次のとおりです。

var temp = m_renderingSurface;
m_renderingSurface = m_outputSurface;
m_outputSurface = temp;
m_d3dDevice.SetRenderTarget(0, m_renderingSurface);

m_renderingSurfaceとは 2 つのレンダーm_outputSurfaceターゲット ( SharpDX.Direct3D9.Surface) で、m_d3dDeviceDeviceExオブジェクトです。

これは美しく機能します。つまり、テアリングはありませんが、数秒後に OutOfMemoryException が発生し、Direct3D には次のデバッグ出力が表示されます。

Direct3D9: (ERROR) :Invalid iBackBuffer parameter passed to GetBackBuffer
Direct3D9: (ERROR) :Error during initialization of texture. CreateTexture failed.
Direct3D9: (ERROR) :Failure trying to create a texture
Direct3D9: (ERROR) :Error during initialization of texture. CreateTexture failed.
Direct3D9: (ERROR) :Failure trying to create a texture
MIL FAILURE: Unexpected HRESULT 0x8876017c in caller: CInteropDeviceBitmap::Present D3D failure
Direct3D9: (WARN) :Alloc of size 1577660 FAILED!
Direct3D9: (ERROR) :Out of memory allocating memory for surfaces.
Direct3D9: (ERROR) :Failure trying to create offscreen plain surface

D3DImage.SetBackBuffer() を呼び出して IntPtr.Zero を渡すことを提案された解決策である関連トピック here を見つけましたが、既存の呼び出しの直前にこれを追加しましたが、問題は解決しませんでした。SetBackBuffer(... IntPtr.Zero) の周りで Lock() と Unlock() を呼び出してみましたが、それでも問題は解決しませんでした。

この時点で、D3DImage にバグがあるのか​​、それともまったく別のアプローチを使用する必要があるのか​​疑問に思っています。代わりに、2 つのレンダー ターゲットを D3D スワップ チェーンに置き換えることはできますか?それにより、SetBackBuffer を常に別のポインターで呼び出す必要がなくなりますか? 私は Direct3D の初心者です。

編集: .NET Reflector を使用して D3DImage.SetBackBuffer() のコードを調べたところ、毎回 InteropBitmap が作成されています。IntPtr.Zero に対しては特に何もしません。これを 1 秒間に何度も呼び出しているため、リソースを解放する時間がない可能性があります。この時点で、2 つの異なる D3DImage を使用し、それらの可視性を交互に切り替えて、常に SetBackBuffer() を呼び出す必要がないようにすることを考えています。

ありがとう。

4

2 に答える 2

0

D3DImage は、バックバッファー ポインターを別のものに設定するたびに新しい Direct3D テクスチャを作成するようです。これは最終的にはクリーンアップされますが、私が行っていたように 1 秒あたり 30 回に設定しても十分な時間が残らず、とにかくパフォーマンスが大幅に低下します。私が行ったアプローチは、それぞれ独自のサーフェスを持つ複数の D3DImage を作成し、それらをすべて重ね合わせて、Visibility プロパティを切り替えて、一度に 1 つだけが表示されるようにすることでした。これは非常にうまく機能しているようで、メモリリークはありません。

于 2013-02-01T01:54:17.183 に答える
0

D3DImage を使用して画像を高速フレームレートで表示すると、同じ問題が発生しました。バックバッファー ポインターを別のポインターに設定すると、D3DImage が新しいテクスチャを作成することがわかりました。しかし、バックバッファ ポインタの内容を変更するだけで (ポインタのアドレスは変更しない)、新しいテクスチャは作成されません。

于 2013-10-14T20:19:52.963 に答える