Using D3DImage on Remote Desktop (RDP)

As of .NET 4.5, WPF’s D3DImage is now finally capable of rendering in RDP. This post will be demonstrating the changes that are needed to render.

D3DImage.SetBackBuffer Method (D3DResourceType, IntPtr, Boolean) was overloaded to include a fallback to software rendering.

public void SetBackBuffer(
	D3DResourceType backBufferType,
	IntPtr backBuffer,
	bool enableSoftwareFallback
)

enableSoftwareFallback
Type: System.Boolean
true to fall back on software rendering; otherwise, false.

Microsoft added some information in their Remarks section that concerns us to successfully implement D3DImage to work in RDP. However it doesn’t explain everything to get D3DImage to work successfully on RDP.

When you call SetBackBuffer(D3DResourceType, IntPtr, Boolean) with the enableSoftwareFallback parameter set to true, the rendering system retains its reference to the back buffer when the front buffer becomes unavailable, so there is no need to call SetBackBuffer when the front buffer is available again. There may be situations where the user’s device becomes unavailable. When that occurs, call SetBackBuffer to release WPF’s reference to the back buffer. If you need to reset your device, call SetBackBuffer with backBuffer set to null, and then call SetBackBuffer again with backBuffer set to a valid Direct3D surface.

When using Remote Desktop, the front buffer becomes unavailable after rendering a single frame. It’s recommended not to release the reference to the back buffer as the front buffer will not become available again even if you release the reference to the back buffer using SetBackBuffer. Note that even if the IsFrontBufferAvailable flag is stating that it is unavailable, you’ll still be able to render properly. The trick is to simply ignore the flag.

Using the Introduction to D3DImage as a example, here are some couple changes that need to occur.

//We don't need to listen to the event anymore
//_di.IsFrontBufferAvailableChanged += OnIsFrontBufferAvailableChanged;

You’ll also need to remove all instances of the IsFrontBufferAvailable flag when rendering.

private void UpdateScene()
{
    //if (_di.IsFrontBufferAvailable && _scene != IntPtr.Zero)
    if (_scene != IntPtr.Zero)
    {
        // lock the D3DImage
        _di.Lock();
 
        // update the scene 
        // (this is a call into our custom unmanaged library)
        SIZE size = new SIZE();
        RenderScene(size);
 
        // invalidate the updated rect of the D3DImage (in this case, the 
        // whole image)
        _di.AddDirtyRect(new Int32Rect(0, 0, size.Width, size.Height));
 
        // unlock the D3DImage
        _di.Unlock();
    }
}