Ab3d.DXEngine Users Guide

 

Troubleshooting


Problems with Ab3d.PowerToys

When MouseCameraController, Camera or EventsManager3D are not working as expected, read the Using Ab3d.PowerToys section.


Compare with WPF 3D rendering

When the rendered image is not as you expected and you are not using any advanced DXEngine features like shadow rendering, stereoscopic rendering or similar, then you can easily compare the results of DXEngine rendering with WPF 3D rendering. To do this you need to WPF 3D rendering - this way your whole code can stay the same and you can easily compare result of DXEngine rendering and WPF 3D rendering.

To do this you need to set the GraphicsProfiles array to contain only the WPF 3D GraphicProfile. This needs to be done before the DXEngine is initialized (for example in the in the constructor after the InitializeComponent) - for example:

public MainWindow()
{
    InitializeComponent();
    MainViewportView.GraphicsProfiles = new GraphicsProfile[] { GraphicsProfile.Wpf3D };
}    

Using DirectX debug layer

DirectX can be used with a special debug layer that can be used to provide some diagnostics information about DirectX usage. When configured correctly, it can display many logging information into a Visual Studio Output window.

Before the debug layer can be used, make sure that it is available on the system. If you have Visual Studio 2015 or newer installed, then the DirectX debug layer is usually installed with Visual Studio. You can check that with checking if you have "Debug - Graphics - DirectX Control Panel" menu item available. If this is not the case, then you can install the DirectX debug layer with installing Windows SDK or if you are on an older system, you can install the DirectX SDK.

After the debug layer is available on the system, you can enable it in DXEngine with adding the following line of code before the DirectX device is created:

    Ab3d.DirectX.DXDiagnostics.CreateDebugDirectXDevice = true;

After CreateDebugDirectXDevice is true, all the DirectX devices will be created with debug layer flag. To check if the DirectX device was actually created with debug layer, check the IsDebugDevice property on the created DXDevice (if CreateDebugDirectXDevice is true, but the IsDebugDevice is still false, the debug layer is not available).

After the DirectX device is created with debug layer, DXEngine can get some additional diagnostics information from the DirectX.

It is also possible to output the DirectX logging information to Visual Studio Output window. To enable this, first open the DirectX Control panel (If you are using Visual studio 2015, you can open it from Debug and then Graphics menu item; otherwise you will need to start it manually from the SDK folder). Then in the scope section click on Edit button and add your application to the list of applications. After that you can specify how much information you want in your Visual Studio output window by checking or unchecking the CheckBoxes for mute settings - if you uncheck all you will get all the info level log messages.

The final step to see the debug into is to start your application with enabled native code debugging - this can be set with opening the project settings and in the Debug section checking the "Enable native code debugging" - this will allow listening to native DirectX messages.

Then start your application and if you did not mute any events you should see many DirectX info messages in the output window.

In case of problems with DirectX rendering, the DirectX debug layer can show very good warning and error messages about the problem. It can also show unreleased DirectX objects. Read more about that below.


Memory usage troubleshooting

DXEngine can create a lot of unmanaged resource that need to be disposed when they are not used any more. To prevent memory leaks, you need to dispose DXViewportView when it is not used any more. If you are manually creating DXEngine resources (DXEngine materials, Effects, Mesh objects and SceneNodes), then you also need to manually dispose all of them.

As written in the last point in the QuickStart section, when you are using DXViewportView and are creating only WPF 3D objects, the only thing you need to do is to dispose the DXViewportView when it is not needed any more. But if you are creating your own DXEngine objects, then you need to dispose all of them (all objects that implement IDisposable: all DXEngine materials, Effects, Mesh objects and SceneNodes).

The easiest way to get hints that your application is having a memory leak is to check memory usage in Visual Studio 2015 Diagnostics window. If the memory usage graph is only rising even when you remove the 3D objects from the scene or remove DXViewportView from the controls three, then this can indicate that some resources may not be disposed.

There are many ways to check for undisposed objects.

  1. When the DXDevice is disposed (call when you dispose the DXViewportView), the DXEngine can show warnings about undisposed objects to the Visual Studio output window. If you suspect that there is a memory leak, please check output window first. But not all undisposed objects are shown there.

  2. To get a better view, you can turn on resource tracking. This can be done with the following code:

    Ab3d.DirectX.DXDiagnostics.IsResourceTrackingEnabled = true;
    SharpDX.Configuration.EnableObjectTracking = true;
    

    This code can be executed at any time (also after the 3D scene was already rendered). From that point on both DXEngine and SharpDX will track the created objects.

    To get a report about resources that were still alive after calling Dispose on DXViewportView, you can use the following code:

    this.Unloaded += delegate(object sender, RoutedEventArgs e)
    {
        // First dispose the DXViewportView
        MainDXViewportView.Dispose(); 
        string dxEngineReport = DXResourceBase.ResourcesTracker.GetTrackedResourcesReport();
        // You can also run the following in Visual Studio Immediate window: DXResourceBase.ResourcesTracker.DumpTrackedResources()
        string sharpDxReport = SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects();
    };                   
    

    Put a breakpoint into the delegate and check the report strings. The most detailed information can be get from SharpDX report. That report also shows the full stack trace from the point at which each object was created.

  3. When the DirectX device is created with debug layer, when native code debugging is enabled in Visual Studio and when at least warn log level is enabled in DirectX Control panel (see previous point for more info), then before the DXDevice is disposed, the DXEngine will initiate a DirectX call to ReportLiveObjects.

    This will show all live DirectX objects in Visual Studio Output window. The following shows a sample report output:

    D3D11 WARNING: Live ID3D11Device at 0x0C5CED14, Refcount: 6 [ STATE_CREATION WARNING #441: LIVE_DEVICE]
    D3D11 WARNING: 	Live ID3D11Context at 0x0C5CFC40, Refcount: 1, IntRef: 1 [STATE_CREATION WARNING #2097226: LIVE_CONTEXT]
    D3D11 WARNING: 	Live ID3DDeviceContextState at 0x0C6BF6F8, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]
    D3D11 WARNING: 	Live ID3D11BlendState at 0x0C6C5674, Name: Opaque, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #435: LIVE_BLENDSTATE]
    D3D11 WARNING: 	Live ID3D11DepthStencilState at 0x0C6C608C, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
    D3D11 WARNING: 	Live ID3D11RasterizerState at 0x0C6C6824, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
    D3D11 WARNING: 	Live ID3D11Sampler at 0x0C6C63DC, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #434: LIVE_SAMPLER]
    D3D11 WARNING: 	Live ID3D11Query at 0x0C5BDA64, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #438: LIVE_QUERY]
    D3D11 WARNING: 	Live ID3D11DepthStencilState at 0x0C6C5EE4, Name: DepthReadWrite, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
    D3D11 WARNING: 	Live ID3D11RasterizerState at 0x0E4A9764, Name: CullClockwise, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
    D3D11 WARNING: 	Live ID3D11Texture2D at 0x0C6CABEC, Name: MSAABackBuffer, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
    D3D11 WARNING: 	Live ID3D11RenderTargetView at 0x0C6CAF04, Name: MSAABackBufferRenderTargetView, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]
    D3D11 WARNING: 	Live ID3D11Texture2D at 0x0E4C2F2C, Refcount: 0, IntRef: 1 [STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
    D3D11 WARNING: 	Live ID3D11DepthStencilView at 0x0C6A5544, Name: DepthStencilView, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #429: LIVE_DEPTHSTENCILVIEW]
    D3D11 WARNING: 	Live ID3D11Buffer at 0x0C3C0FCC, Name: DirectionalLightShader_perFrameCameraConstantsBuffer, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #423: LIVE_BUFFER]
    D3D11 WARNING: 	Live ID3D11Buffer at 0x0E70AB0C, Name: DirectionalLightShader_perFrameDirectionalLightsConstantsBuffer, Refcount: 0, IntRef: 0 [STATE_CREATION WARNING #423: LIVE_BUFFER]
    D3D11 WARNING: 	Live ID3D11Buffer at 0x0E7111AC, Name: DirectionalLightShader_perObjectNoWVPConstantsBuffer, Refcount: 1, IntRef: 0 [STATE_CREATION WARNING #423: LIVE_BUFFER]
    

    To see if there are any undisposed objects, you need to check if the "Refcount" number is bigger than 0. This means that there are still some outer references to that object. If "IntRef" is bigger than zero, than this is not a problem because this shows internal references that will be automatically disposed. To show this report, there still need to be some outer references live for ID3D11Device (usually 6) and ID3D11Context (usually 1). If you see some references there, this is not a problem because those references will be released when the DXDevice is disposed. In the sample text above, there is only one object that was not property disposed - it is shown in the last line with Recount set to 1: DirectionalLightShader_perObjectNoWVPConstantsBuffer

  4. If you have found a memory leak, please check that you are disposing all the created objects (see the stack trace in SharpDX report). If you have correctly disposed all the objects and still see some undisposed objects, please gather as many data as possible and send that to support@ab4d.com.


Receiving warning and error messages

With release build of DXEngine it is possible to get all the warning and error log messages (debug build enables getting also info and debug log messages). Note that logged error messages are not exceptions but log messages that describe some error state in the DXEngine. To enable logging, set the following properties in the static Ab3d.DirectX.DXDiagnostics class:

  • set CreateDebugDirectXDevice to true - this will use debug layer on DirectX device and can report problems with using DirectX API
  • set LogLevel to Ab3d.DirectX.DXDiagnostics.LogLevels.Warn
  • set LogFileName to "desktop" - this will write all log messages to DXEngine.log on the user's desktop (you can also specify a full file name - for example "c:\temp\DXEngine.log")

For example:

Ab3d.DirectX.DXDiagnostics.CreateDebugDirectXDevice = true;
Ab3d.DirectX.DXDiagnostics.LogLevel = DXDiagnostics.LogLevels.Warn;
Ab3d.DirectX.DXDiagnostics.LogFileName = "desktop"; // or use full file name for example @"c:\temp\DXEngine.log";

Enabling logging might get you some additional information about the problems and might lead to the solution for them.

You can also set the IsWritingLogToOutput to get the log messages to Visual Studio's Output window and LogAction to get all log messages in any custom method that you want.

Note that you need to set those properties before the DirectX device is created (for example in the constructor of the main window before calling InitializeComponent).


Support

You can always ask for support by sending an email to support@ab4d.com (having a log file, screenshot from WPF 3D and DXEngine rendering or a sample project to reproduce the problem will help a lot).