1
\$\begingroup\$

I have a 3d window hosted inside a WPF program. This is written in C#, using SlimDX. It uses a D3DImage subclass to support dx10 & dx11 rendertargets, like this site recommends: http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/437/Direct3D-10-11-Direct2D-in-WPF.aspx

However, when I resume from sleep, or even lock & unlock the screen on Windows, the 3D window goes blank until I resize it. What is the appropriate way to mitigate this issue?

After resuming, but while the 3D window is still blank, I've confirmed:

  • The window ActualWidth & ActualHeight have not changed
  • The device is not null
  • The backbuffer is not null
  • The draw loop is still looping
  • The blank screen is occurring after the unlock. To prove this I put a Thread.Sleep() in the Unlock handling code to purposely lock the UI thread. The 3D image was still visible until the thread.sleep period ended, then it went blank.
\$\endgroup\$
  • \$\begingroup\$ To add to this, though the 3D window is properly drawn after I manually resize the window, simply calling the Resize() function after an unlock is detected does not fix the blank screen. \$\endgroup\$ – Brandon Jun 4 '15 at 18:35
  • \$\begingroup\$ To my knowledge, the reason for this is that the rendering buffer in the DirectX context is freed when going into sleep or lock mode, causing it to render nothing afterwards. Though my knowledge about this is too limited to post an actual answer. \$\endgroup\$ – Alexandre Desbiens Jun 4 '15 at 19:57
1
\$\begingroup\$

On resume from sleep/lock/ctrl-alt-delete the backbuffer needs to be reset. Because the backbuffer doesn't go grey until a halfsecond or so after resume, either find a way to detect that the backbuffer needs a reset, or wait an arbitrary amount of time. (Don't lock the UI!)

//Add to initialization code
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;

...

private async void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
    if (e.Reason == SessionSwitchReason.SessionUnlock)
    {
        await Task.Delay(1000);
        if (MBackBufferTex != null)
        {
            Md3DImage.SetBackBuffer11(MBackBufferTex);
        }
    }
}
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

I found a solution to this through vigorous searching, you can directly get the pointer reference from your bufferTexture within your D3DImage.

D3DImage has a non-public member called "_pUserSurfaceUnsafe", when your D3DImage goes blank from ctrl+alt+delete, locking or sleeping then "_pUserSurfaceUnsafe" loses its reference and becomes 0 (null pointer).

This part will return the reference to the field.

System.Reflection.FieldInfo surfaceReference = _d3dImage.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Single(pi => pi.Name == "_pUserSurfaceUnsafe");

This part will get you the value from your field reference.

object surfaceValue = surfaceReference.GetValue(_d3dImage);

You just have to test if the value is 0 or not equal to your bufferTexture and go from there. :)

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.