I am using D3DImage to display a sequence of frames that are rendered unto the same Direct3D Surface one after the other. My current logic is thus:
- Display last rendered frame (i.e.D3DImage.Lock()/AddDirtyRect()/Unlock())
- Start rendering next frame
- Wait for next frame to be ready and that it's time to display it
- Display last rendered frame
- ...
The problem with this approach is that when we are done calling Unlock() on D3DImage, the image isn't actually copied, it's only scheduled to be copied on the next WPF render. It's therefore possible that we render a new frame on the Direct3D surface before WPF has had the chance to display it. The net result is that we see missed frames on the display.
Right now I'm experimenting with using a separate Direct3D texture for rendering and performing a copy to a "display texture" just before display, which is giving better results but incurs substantial overhead. It would be preferrable to just be able to know when D3DImage is done refreshing and start rendering the next frame immediately after. Is this possible, if so how? Or do you have a better idea altogether?
Thanks.
CompositionTarget.Rendering
help? – SecundasCompositionTarget.Rendering
as a trigger to callUnlock()
(if your render is ready) on yourD3DImage
and schedule another render? This means you would only ever be rendering and displaying images at most (but possibly less than) at WPF's frame rate. – SecundasUnlock()
you can immediately start another render into yourD3DImage
. CallingLock()
will block until the WPF render thread has copied the back buffer to the front buffer. Once you've finished your render, you would wait until the nextCompositionTarget.Rendering
before callingUnlock()
and repeating the process again. It simply doesn't matter if you finish rendering before the control is redrawn, because it's redrawing from the front buffer, not the back buffer (which is what you're modifying). – SecundasAddDirtyRect()
? Also, the IsFrontBufferAvailableChanged event might be helpful. – Signally