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_d3dDevice
はDeviceEx
オブジェクトです。
これは美しく機能します。つまり、テアリングはありませんが、数秒後に 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() を呼び出す必要がないようにすることを考えています。
ありがとう。