VS2012 Graphics Debugger

Started by
10 comments, last by alexisgreene 11 years ago

I have ran into a major problem while rewriting my rendering code to take advantage of the mutithreading features of D3D11. I fired up the graphics debugger to see what is going on. Everything works fine with it except for the graphics pipeline stages viewer. When I click on it, the loading indicator shows up and never goes away. Has anyone else run into this problem?

Advertisement

I get the same behavior/problem - it seems that the pipeline view is not working properly for draw calls on deferred contexts...

Well that is just awful. I guess I will have to spend a day doing through all my code line by line...

Yes, unfortunately deferred contexts are not currently supported.

throw table_exception("(? ???)? ? ???");

The support for multithreaded rendering is (very) likely to be improved in future iterations of the debugger. I know that doesn't help you now, but at least there will be some help coming down the road...

Well I took the advice you gave me when I began rewriting my rendering code and made the engine able to hot swap between multi-threaded rendering with deferred contexts and single threaded rendering using only the immediate context. Turns out using the graphics pipeline viewer was no help at all to me... I was accidentally swapping the stride and offset values when I set the vertex buffer for the input assembler. I had to compare IDeviceContext states of the new build and a build before the rewrite in order to catch that mistake.

Nice - and how do you like the system with swappable threading? When I implemented the one for Hieroglyph 3, I found that it helps you get a much better feel for what your algorithms are doing and where you are making assumptions (i.e. relying on a previously set state) and what you are spending your API calls on.

Do you have any debugging tips or experience that you can share?

Having swappable threading is amazing because it forces you to truly understand what is going on under the hood and gives you an amazing debugging tool at the same time. This new and basic understanding of the pipeline stages and immediate vs deferred contexts made me realize how sloppy and inefficient my previous rendering code was. My laptop (a.k.a. development rig) has a really crappy Intel graphics card (DX10 - limited multi-threading) and a pretty beefy (at least for a laptop) nVidia graphics card (DX11). It is really nice to see my engine run optimally on each graphics card.

Tip #1

State management was, or rather still is, a huge challenge. In order to avoid unnecessary state changes (single-threaded) I came up with a somewhat simple approach. Every state change function (ex. IASetIndexBuffer()) will set a "desired" variable if it differs from a "current" variable, as well as pushing a function pointer (ex. ApplyIASetIndexBuffer()) to a vector named "m_PendingStateChanges". The variables I just mentioned are simply the variables that I would pass to the actual API function.

ApplyState() just iterates though the vector, utilizing all function pointers it contains to call only the necessary Apply*() functions. Those Apply*() functions simply submit the state change to the API and then update the "current" and "desired" variabes. This system of handling state changes eliminates unnecessary stage changes as well as eliminating having to test each individual pipeline state once ApplyState() is called.

Currently I do this on a per context basis, passing "true" to FinishCommandList() in order for all the deferred contexts to behave nicely with each other. The D3D11 docs explicitly state that this is inefficient. I am currently trying to find a way to pull state changing away from the context level and closer to the device level. In theory, there is only one immediate context so there should only be one "pipeline state manager". Finding a way for this to play nice with multiple contexts in a multi-threaded scenario, as well as not breaking hot swapping, is the challenge.

Tip #2

When things work good, fire up the graphics debugger and save a snapshot. Clicking the device context of a good draw call will give you detailed information of the entire pipeline. Since you have no visual pipeline stages while using deferred contexts, having a snapshot of what the device contexts should look like (state-wise) is the next best thing. Even without a good snapshot saved, you can scan over the values and possibly spot the problem.

Tip #3

Consider using http://threadingbuildingblocks.org/ over managing threads manually. This book http://www.amazon.com/Intel-Threading-Building-Blocks-Parallelism/dp/0596514808/ref=sr_1_1?ie=UTF8&qid=1334719817&sr=8-1 is a must have should you choose to use TBB. Scalable, automatic (and even manual) task dispatching, and concurrent safe containers and allocators are just a few of the things this library offers.

These are just the top 3 I could come up with off the top of my head.

I'm glad you've found the source of your problems Deortuka, but as a follow up to your original question and to help others in the future, I'd like to share that Visual Studio Update 2 was made available today, with enhanced support for multithreaded rendering.

The following describes the process that should make Graphics Diagnostics more helpful in Multithreaded scenarios in the future:

1) After capturing graphics information from a multithreaded renderer, in the Event List, expand the command list to see the draw calls. For example:
1 :: DeviceContext::Draw(foo)
2 :: DeviceContext::IASetBlahBlah
3 :: DeviceContext::ExecuteCommandList
4 :: DeviceContext::Draw(foo)

2) The Pipeline Stages window will work when a Draw call under ExecuteCommandList is chosen, because these Draw events represent execution of the draw call.

3) With that Draw call (event 4 in this example) selected, things should work normally.

When the first Draw call (event 1) is selected, you should see this message in the Pipeline Stages window “Pipeline stages are not computable for deferred context draws/dispatches. Please examine the children of ExecuteCommandList instead.” This message is meant to direct you to the right place.

Good luck with your renderer!

throw table_exception("(? ???)? ? ???");

The timing on that update couldn't of come at a better time! Thanks for that information.

This topic is closed to new replies.

Advertisement