Realtime graph for WPF

You know the Task Manager’s CPU Usage History graph that shows CPU utilization over time? Try that type of the graph in WPF and you’ll realize that it isn’t as easy as it should be due to the WPF’s performance for real time graphs. Which sucks due to the way WPF works. Even with 3rd party you’ll have hard time to find a graph fast enough to cope with even more than few hundred samples.

Hence I’ve decide to build my own real time graph. It is based on Direct2D because Direct2D is much faster when it comes to presenting the graphical result. However, merging Direct2D into WPF is, again, not an easy task as it should be (hint to MS – there should be native WPF support for hosting Direct2D output). Anyway, I found the article Using Direct2D with WPF on CodePlex. It comes with sources which I use. Those sources require Windows API CodePack(WACP), a bug ridden set of managed API’s to various, otherwise unsupported, features (MS went with this approach (if it works, it works, if it doesn’t fix it by yourself) instead of providing an official support). The WACP binaries I provide are compiled from 1.1. sources with some bug fixed regarding DirectCompute.

Here is a snapshot from a graph showing a sinusoide as a product of many samples (the attached example contains required code and binaries).

realtimechart

I utilize a combination of Direct2D and samples optimization which yields smooth result even with million and more samples.

 

Required code

Create a class that implements IGraphItem interface. This class will hold a single sample through Time and Value property. Time typically represents a time elapsed since the start and it is expressed in millisecond while Value is a double and holds whatever value.

public class RealtimeGraphItem : IGraphItem
{    
    public int Time { get; set; }
    public double Value { get; set; }
}

Configure RealtimeGraphControl like

xmlns:rg="clr-namespace:Righthand.RealtimeGraph;assembly=Righthand.RealtimeGraph"
...
<rg:RealtimeGraphControl x:Name="Graph" AxisColor="Blue" AxisWidth="1"      VerticalLinesInterval="5" VerticalLabelsStep="2"  SpanX="100"
      MaxY="250" MinY="50"  HorizontalLinesInterval="10"/>

where SpanX is time span expressed in seconds telling the graph how many seconds are shown.

Finally create a BindingList<RealtimeGraphItem> source and bind it to Graph.SeriesSource property (BindingList is required as it has the event ListChanged that is used to trigger rendering update of the graph). And that’s it. When you add new items to the source the graph will automatically reflects the new state.

 

Requirements

.net 4.0

Dowload

Attached are binaries and the sources for the Example project.

Let me know what you think.

RealtimeGraph_1_0.zip (1.31 mb)

Capture DirectX 10/11 debug output to Visual Studio

Working with default DirectX configuration in a Visual Studio project is like working with a black box. Even more so when you have a managed code project. Mostly you’ll get an ArgumentException saying “Additional information: Value does not fall within the expected range.” or something like that, almost totally not helpful. But fear not, there is a way to capture a ton of useful information right into Visual Studio’s Debug output window. And here is how:

0. I assume you have DirectX SDK already installed.

If not download if it from DirectX Developer Center.

1. Enable debug output in DirectX control panel

a) Go to Start/All Programs/Microsoft DirectX SDK ([Month] [Year])/DirectX Utilities [(64-bit)] and run DirectX Control Panel [(64-bit)]

image

b) Go to Direct3D 10.x/11 tab. Except for the Edit List… button everything is disabled. The reason is that you have to add applications you wish to debug beforehand you can alter the settings (this is not obvious and UI is really clumsy here).

image

c) Click Edit List… and add your application to the List of process or folders. Clicking on […] button and selecting application exe file does the trick. Click OK button to close this window.

d) Next step is to actually enable debugging of the application. This can be done in two ways – either select Debug Layer’s Force On or switch on debugging directly from code (shown later in step 2.). You can select which messages won’t be displayed through Mute settings.

image

2. Alternatively to enabling debugging from step 2d)

You can create the DirectX device in code with CreateDeviceOptions.Debug option, like the code below when using managed code and Windows API Codepack:

D3DDevice device = D3DDevice.CreateDevice(null, DriverType.Hardware, null, CreateDeviceOptions.SingleThreaded | CreateDeviceOptions.Debug, levels);

This option will work with both Applications Controlled and Force On Debug Layer settings but not with Force Off.

3. Enable unmanaged debug output in Visual Studio project

The final step is to allow showing unmanaged debug output in Visual Studio debug output window. This works by default in an unmanaged project but not in managed projects. Note that it is a per-project setting.

Open project properties, Debug tab and make sure that Enable unmanaged code debugging option is checked.

image

Here you go. You’ll see plenty of DirectX messages in Debug output window from DirectX such as:

image

A managed path to DirectCompute

About DirectCompute

After NVidia Cuda, OpenCL we got DirectX’s version (of GPGPU parallelism for numerical calculations) named DirectCompute. All three technologies are very similar and have one goal: to provide some sort of API and shader language for numerical calculations that GPGPU is capable of. And if you use it wisely the performance gains over normal CPU are huge, really huge. Not just that you offload CPU but the calculations due to GPGPU massive multithreading (and multicore) are much faster compared to even the most advanced x64 CPU.

It works like this: you prepare enough data that can be worked on in parallel, send it to GPGPU, wait till GPGPU finished processing the data and fetch the results back to the CPU where your application can use them. You can achieve up to a TFLOP with a graphics card sold today.

I guess this information is enough to see what is all about. For more information on the topic check out  Cuda and OpenCL. I’d suggest to check out the DirectCompute web site but the reality is that I couldn’t find any official (or non-official) page that deals with it (it is the youngest of the three but still that could be more online information, don’t you think). However you might check the DirectCompute PDC 2009 presentation here and a simple tutorial.

Of the three I am most interested in DirectCompute because:

  1. Cuda is tied to NVidia GPGPU while OpenCL and DirectCompute aren’t
  2. I prefer using DirectX over OpenGL for a simple reason – I did work for a client using DirectX so I am more familiar with it

I have a NVidia silent GeForce 9600 series graphic card (cards from GeForce 8 and up are supported) and the good news is that NVidia has been supporting CUDA for a while and recently introduced support for DirectCompute as well. OpenCL is also supported. I don’t know the current state of support for ATI cards.

There is a potential drawback if you go with DirectCompute though. It is a part of DirectX 11 and will run on Windows 7, Windows 2008 and Vista SP2 (somebody correct me). The problem is if you have an older Windows OS like Windows XP or you want support older Windows. In that case you might consider alternatives.

Goal

The not that good aspect of a young technology such as DirectCompute is lack of samples, documentation and tutorials are almost nonexistent. What’s even worse for a .net developer as I am is apparent lack of managed support. Which turns to be there to some extent through Windows API Code Pack (WACP) managed code wrappers. Note, WACP isn’t very .netish such as Managed DirectX was but it is good enough.

So I tried the managed approach for BasicCompute11 C++ sample (that comes with DirectX SDK) through WACP and here are the steps to make it run. It should give you a good starting point if you are DirectComputing through managed code and even if you are using native code. Hopefully somebody will benefit from my experience.

BasicCompute11 sample is really a simple one. It declares a type holding an int and a float, creates two arrays of those with an incremental value ( {0, 0.0}, {1, 1.1}, {2, 2.2}, ….{8191, 8191.0}) and adds them together to a third array.

I’ll be working on Windows 7 x64 with NVidia GeForce 9600 graphics card but will create a Win32 executable.

Steps

1. Install the latest NVidia graphics drivers. Current version 195.62 works well enough.

2. Install Windows 7 SDK. It is required because WACP uses its include files and libraries.

3. Make sure that Windows 7 SDK version is currently selected. You’ll have to run [Program Files]\Microsoft SDKs\Windows\v7.0\Setup\SDKSetup.exe. Note that I had to run it from command prompt because it didn’t work from UI for some reason.

4. Install DirectX SDK August 2009 SDK.

  • If it doesn't exist yet then declare an environment variable DXSDK_DIR that points to [Program Files (x86)]\Microsoft DirectX SDK (August 2009)\ path.
    image

5. Install Windows API Code Pack. Or better, copy the source to a folder on your computer. Open those sources and do the following:

  • Add $(DXSDK_DIR)Include path to Include folder
    image
  • And $(DXSDK_DIR)Lib\x86 to libraries
    image

After these settings the project should compile. However, there are additional steps, because one of the methods in there is flawed. Let’s correct it.

  • Open file Header Files\D3D11\Core\D3D11DeviceContext.h and find method declaration 
    Map(D3DResource^ resource, UInt32 subresource, D3D11::Map mapType, MapFlag mapFlags, MappedSubresource mappedResource);
    (there are no overloads to Map method). Convert it to
    MappedSubresource^ Map(D3DResource^ resource, UInt32 subresource, D3D11::Map mapType, MapFlag mapFlags);
  • Open file Source Files\D3D11\Core\D3D11DeviceContext.cpp and find the (same) method definition
    DeviceContext::Map(D3DResource^ resource, UInt32 subresource, D3D11::Map mapType, D3D11::MapFlag mapFlags, MappedSubresource mappedResource)
    Replace the entire method with this code:
    MappedSubresource^ DeviceContext::Map(D3DResource^ resource, UInt32 subresource, 
    D3D11::Map mapType, D3D11::MapFlag mapFlags) { D3D11_MAPPED_SUBRESOURCE mappedRes; CommonUtils::VerifyResult(GetInterface<ID3D11DeviceContext>()->Map( resource->GetInterface<ID3D11Resource>(), subresource, static_cast<D3D11_MAP>(mapType), static_cast<UINT>(mapFlags), &mappedRes)); return gcnew MappedSubresource(mappedRes); }

DirectX wrappers we need are now functional. Compile the project and close it.

6. Open DirectX Sample Browser (you’ll find it in Start\All Programs\Microsoft DirectX SDK (August 2009) and install BasicCompute11 sample somewhere on the disk.

image

7. Open the sample in Visual Studio 2008 and run it. The generated console output should look like this:

image Pay attention to the output because if DirectX can’t find an adequate hardware/driver support for DirectCompute it will run the code with a reference shader – using CPU not GPGPU (“No hardware Compute Shader capable device found, trying to create ref device.”) or even won’t run at all.

If the sample did run successfully it means that your environment supports DirectCompute. Good for you.

8. Now try running my test project (attached to this article) that is pure managed C# code. It more or less replicates the original BasicCompute11 sample which is a C++ project. The main differences with the original are two:

  • I removed the majority of device capability checking code (you’ll have to have compute shader functional or else…)
  • I compile compute shader code (HLSL –> FX) at design time rather at run time. This is required because there are no runtime compilation managed wrappers in WACP because those are part of D3DX which isn’t part of the OS but rather redistributed separately. So you have to rely on FXC compiler (part of DirectX SDK). A note here: I’ve lost quite a lot of time (again!) figuring out why FXC doesn’t find a suitable entry point to my compute shader code when compiling (and errors out). I finally remembered that I’ve stumbled upon this problem quite a long time ago: FXC compiles only ASCII(!!!!!) files. Guys, is this 2009 or 1979? Ben 10 would say. “Oh man.”
    Anyway, the FX code is included with project so you won’t have to compile it again. This time the output should look like this:
    image

I didn’t document my rewritten BasicCompute11 project. You can search for comments in the original project.

Conclusion

Compute shaders are incredibly powerful when it comes to numerical calculations. And being able to work with them through managed code is just great. Not a lot of developers will need their power though, but if/when they’ll need them the support is there.

As for final word: I miss documentations, tutorials and samples. Hopefully eventually they’ll come but for now there is a good book on CUDA (remember, the technologies are similar) – the book comes in a PDF format along NVidia CUDA SDK.

Have fun DirectComputing!

DirectComputeManaged.zip (2.05 mb)

DirectX HLSL compiler chokes on unicode sources

In a week or so I've created two HLSL effects in two different .fx files. While they were really simple and straightforward, one of them failed to load at runtime in my managed DirectX 3D application (yet both worked in NVidia FX Composer). Why would one fail while another is working? The error information was really non existent (i.e. "there was an error in the application" - DirectX, thanks so much for all of the details...). So I tried the fxc compiler that comes with DirectX SDK. The problematic effect didn't compile, of course. This time the error was more verbose but highly misleading:

ID3DXEffectCompiler: There were no techniques

The problem with this message was that I had a technique defined (remember, the thing was working in FX Composer). Hm. Google didn't help me at all. Then I went with my standard problem solving approach (SPSA) - eliminate pieces step by step (take a working sample and modify it slowly step by step to pinpoint the problem). Ok, so I copied the working effect content into non-working file opened in editor (I did copy&paste of the code, not the file). I tried fxc again and to my surprise it yelled the same error at me. What? How could it be? The content was the same. Perhaps I've drank too much coffee today? So I used KDiff3, a file comparison tool (free), to compare both files. On opening it warned me that while the content is the same the binary content isn't. This info finally triggered my brains - it has to be the unicode signature prefix. To be sure I fired yet another free utility, this time a hex editor called HxD. And there is was a hex prefix of EF BB BF meaning an UTF-8 encoded text. We live in an unicode universe for a bunch of years now and I guess fxc should work with non-ASCII files as well. Or at least it should complain that file isn't an ASCII one.