Direct3D11 Multithreading

Started by
6 comments, last by Alessio1989 8 years, 7 months ago

Haven't found a single example or tutorial explaining this. Can someone post some information and example code on this to guide me? I don't wanna do this for performance reasons. I just want to learn multithreaded programming in directx.

Advertisement
The device can be used by any thread. Feel free to load textures/models etc on any or all threads.

Contexts can only be used by one thread (at a time), but you can create as many (deferred) contexts as you need.

When you've finished submitting draw calls to a deferred context, you can call FinishCommandList to turn it into a ID3D11CommandList. You can then hand this over to your "main" thread (the one that owns the immediate context), and it can call ExecuteCommandList to send those commands to the GPU.

tl;dr-
Main thread owns "immediate context" and submits command lists.
Worker threads own "deferred contexts" and create command lists.
Every thread can use the device.

The device can be used by any thread. Feel free to load textures/models etc on any or all threads.

Contexts can only be used by one thread (at a time), but you can create as many (deferred) contexts as you need.

When you've finished submitting draw calls to a deferred context, you can call FinishCommandList to turn it into a ID3D11CommandList. You can then hand this over to your "main" thread (the one that owns the immediate context), and it can call ExecuteCommandList to send those commands to the GPU.

tl;dr-
Main thread owns "immediate context" and submits command lists.
Worker threads own "deferred contexts" and create command lists.
Every thread can use the device.

From what I know, you use threads to do work in parallel to load as many resources as possible at a time. But In std::threads, to make it work properly, I've to use thread.join() with mainthread for the mainthread to wait for that thread to finish the execution. Doesn't this completely destroy the purpose of threads? This is just like calling functions then.

From what I know, you use threads to do work in parallel to load as many resources as possible at a time. But In std::threads, to make it work properly, I've to use thread.join() with mainthread for the mainthread to wait for that thread to finish the execution. Doesn't this completely destroy the purpose of threads? This is just like calling functions then.


No, because you can launch multiple threads and then join on all of them. This means you can have X functions executing in parallel. This is often called a fork-join model.

That said, use a thread pool and a job system instead of spinning up a new thread for every function call. Threads are heinously expensive to spin up and tear down on many platforms, and they're still somewhat expensive everywhere else. The job system can still be used in a fork-join for simplicity, of course.

Sean Middleditch – Game Systems Engineer – Join my team!

Just so that you know ahead of time, it's unlikely that you'll get any significant performance gains out of D3D11 deferred contexts. Unfortunately the way that the API is structured prevents most drivers from actually building command buffers ahead of time, and so you still end up serializing a lot of the work. However with that said, it could still definitely be a good learning experience. It can also help you get your engine ready for D3D12 and/or Vulkan, where multithreading is actually useful.

By the way, there is a multithreaded rendering sample available on MSDN.
Yeah don't use fork-join in a game engine, it's not suitable.

Probably best to implement a threading system and apply it to some of your own code as a learning exercise before applying it to the D3D API.

The job model is very popular in game engines these days:
http://fabiensanglard.net/doom3_bfg/threading.php

Or alternatively, check out Intel TBB.

As @MJP said you are unlikely to gain much performance using deferred contexts with D3D11 *unless* you are doing a lot of CPU intensive work that for whatever reason you cannot separate from your rendering logic *and* can actually be parallelised.

I've got a C#/SharpDX example https://github.com/spazzarama/Direct3D-Rendering-Cookbook/tree/master/Ch10_01DeferredRendering. You may need to take a good look at the code to work out how to drive it as it is assumed you are reading the book at the same time.

Justin Stenning | Blog | Book - Direct3D Rendering Cookbook (using C# and SharpDX)

Projects: Direct3D Hook, EasyHook, Shared Memory (IPC), SharpDisasm (x86/64 disassembler in C#)

@spazzarama

 

Note that only NVIDIA drivers support driver command lists, on all other HIVs there is the runtime emulation behind the scene with the possibility of performance loss.

"Recursion is the first step towards madness." - "Skegg?ld, Skálm?ld, Skildir ro Klofnir!"
Direct3D 12 quick reference: https://github.com/alessiot89/D3D12QuickRef/

This topic is closed to new replies.

Advertisement