Adding and Removing External Monitors causes DeviceRemoved Crash
#1
I'm currently a little stumped with a crash in my application that's happening because of a DeviceRemoved exception that's being thrown:

Code:
<InnerException>
<ExtendedInformation>
<ResultCode>HRESULT = 0x887A0005</ResultCode>
<Descriptor>HRESULT: [0x887A0005], Module: [SharpDX.DXGI], ApiCode: [DXGI_ERROR_DEVICE_REMOVED/DeviceRemoved], Message: </Descriptor>
<HResult>-2005270523</HResult>
</ExtendedInformation>
<Message>HRESULT: [0x887A0005], Module: [SharpDX.DXGI], ApiCode: [DXGI_ERROR_DEVICE_REMOVED/DeviceRemoved], Message: </Message>
<Source>Ab3d.DXEngine</Source>
<StackTrace> at Ab3d.DirectX.CompleteRenderingStep.b(DXDevice a, Boolean b) at Ab3d.DirectX.CompleteRenderingStep.OnRun(RenderingContext renderingContext) at Ab3d.DirectX.RenderingStepBase.Run(RenderingContext renderingContext) at Ab3d.DirectX.DXScene.ao(RenderingContext a) at Ab3d.DirectX.DXScene.am(RenderingContext a, Boolean b, Boolean c, DXScene d)</StackTrace>
<TargetSite>Boolean b(Ab3d.DirectX.DXDevice, Boolean) @ Ab3d.DirectX.CompleteRenderingStep</TargetSite>
<Type>SharpDX.SharpDXException</Type>
</InnerException>
<Message>Device removed in RenderScene The most probable reason for this error is that the graphics driver was updated while the application was running. DeviceRemovedReason: HRESULT: [0x887A0007], Module: [SharpDX.DXGI], ApiCode: [DXGI_ERROR_DEVICE_RESET/DeviceReset], Message: The GPU will not respond to more commands, most likely because some other application submitted invalid commands. The calling application should re-create the device and continue. </Message>
<Source>Ab3d.DXEngine</Source>
<StackTrace> at Ab3d.DirectX.DXScene.HandleDeviceRemoved(String message, SharpDXException sharpDxException) at Ab3d.DirectX.DXScene.am(RenderingContext a, Boolean b, Boolean c, DXScene d) at Ab3d.DirectX.DXScene.RenderScene(Boolean forceRender, Boolean forceUpdate) at Ab3d.DirectX.Controls.DXView.RenderScene(Boolean forceRender, Boolean forceUpdate) at Ab3d.DirectX.Controls.DXView.j(Object a, EventArgs b) at System.EventHandler.Invoke(Object sender, EventArgs e) at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget) at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)</StackTrace>
<TargetSite>Void HandleDeviceRemoved(System.String, SharpDX.SharpDXException) @ Ab3d.DirectX.DXScene</TargetSite>
<Type>Ab3d.DirectX.DXEngineException</Type>


For context, this is specifically happening when a monitor is connected or disconnected from the computer, including when a computer goes to sleep and disconnects/reconnects to its monitors, although it's somewhat sporadic. It most consistently happens when I maximize the application, reduce it again, and then plug or unplug a monitor. My initial instinct is that it's related to the resolution changing/the swap buffer being resized as mentioned in the Microsoft docs but it doesn't explain some of the crash scenarios.

My current setup a WPF Viewport3D wrapped in the DXViewportView, with the DirectXImage presentation type. Our application is a VB.NET/WPF app, target framework is .NET 4.8.

I've done a few other troubleshooting steps if it's helpful at all:
  • I've reproduced this issue on multiple different Windows computers - I believe they were all Windows 11, but could be wrong. 
  • I've gotten this crash by unplugging and replugging one or more monitors, regardless of if the application is currently displayed on the monitor - but not all the time. Again, it seems to always happen if the application has been maximized/full screen at any point while it's running, and then the monitors change. Otherwise, it happens about 1 in 3 times that I plug/unplug a monitor.
  • Manually changing the resolution of a monitor doesn't seem to cause the crash.
  • Changing the presentation type of the viewport to DirectXOverlay seems to solve the issue. I can't tell for certain, but running the software with the presentation type changed, I've been able to do at least 10 cycles of connecting and disconnecting monitors, full screen and not, without any crashes. Unfortunately, we have a few WPF overlays and backgrounds that make switching over to that presentation type a little difficult. If it's the only fix, I could try and make it work, but would prefer to stick with DirectXImage for now. I'm also not 100% confident that it does fix the issue since... I'm not sure what's causing it to begin with.
  • I can reproduce this in the target .NET 4.8 version of the DXEngine samples app. I haven't been able to reproduce it in the .NET 8.0 version, but going back to the olden days of 4.8 and unplugging/replugging the monitors crashes it with a similar error to my own application.

I know this is a bit of a shot in the dark, but I'm hoping there's some guidance for what I might be doing wrong or missing in my application, or if this is a bug somewhere further than my application (and hopefully a fix for it too!). It might just be a 'need to update WPF and .NET framework' as well. Happy to provide more code/context for how it's setup - I'm pretty new to DXEngine!

As an aside, I'm working on adding in a handler for the DXEngine DeviceRemoved event so that we can handle it gracefully and save/reload all the visual data, but would still like to find the root cause of the issue/bug since it seems like it's probably not intended behavior and the DXGI error shouldn't be raised here (I think?).
#2
I can reproduce the problems with changing monitors on Windows 11.

Similar errors appeared in the past, but they were fixed by using the Microsoft.Win32.SystemEvents.DisplaySettingsChanging and Microsoft.Win32.SystemEvents.DisplaySettingsChanged events - in the event handler the code disposes the current D3DImage and also checks if the primary device is changed.

I have testes this on Windows 10 and this still works.

But on Windows 11, when I change the display from the external monitor to the primary monitor (on laptop), I get both events but still the application crashes with UCEERR_RENDERTHREADFAILURE error (WPF render thread crash). Even worse is when I change the display from the primary monitor to the external display. In this case the app just freezes without any exception even before any of the previously mentioned events happen.

I will try to provide the solution for the first case (in case when I get the events). I am not sure what to do in case when the app is not notified on the display change.

It seems that there are some internal changes from Window 10 to Windows 11 that break this. Hopefully I will be able to solve at least some of the cases.
Andrej Benedik
#3
It seems that when the window is set to full screen and when the primary monitor is changed, then on Windows 11 the SizeChanged event is called before the Microsoft.Win32.SystemEvents.DisplaySettingsChanging event. Because of this the DXEngine resized the existing D3DImage objects but the backend adapter was not valid anymore - this lead to a crash.

I have updated the code to check if the current adapter is still valid when the SizeChanged event occurs. If it is not valid anymore, then the D3DImage is not resized but it waits for the Microsoft.Win32.SystemEvents.DisplaySettingsChanging and Microsoft.Win32.SystemEvents.DisplaySettingsChanged events to be recreated.

I have sent the fix to the ohmyizzy who reported this issue. Hopefully, he will also report that this is solved.
Andrej Benedik
  


Forum Jump:


Users browsing this thread:
1 Guest(s)