YoonSeok OH
YoonSeok OH

Reputation: 745

Multithreading in Direct 3D 12

Hi I am a newbie learning Direct 3D 12.

So far, I understood that Direct 3D 12 is designed for multithreading and I'm trying to make my own simple multithread demo by following the tutorial by braynzarsoft.

https://www.braynzarsoft.net/viewtutorial/q16390-03-initializing-directx-12

Environment is windows, using C++, Visual Studio.

As far as I understand, multithreading in Direct 3D 12 seems, in a nutshell, populating command lists in multiple threads.

If it is right, it seems

is enough for a single window program.

I wonder

Q1. When do we need multiple command queues?

Q2. Why do we need multiple fences?

Q3. When do we submit commands multiple times?

Q4. Does GetCPUDescriptorHandleForHeapStart() return value changes?

Q3 comes from here.

https://developer.nvidia.com/sites/default/files/akamai/gameworks/blog/GDC16/GDC16_gthomas_adunn_Practical_DX12.pdf

Purpose of Q4 is I thought of calling the function once and store the value for reuse, it didn't change when I debugged.

Rendering loop in my mind is (based on Game Loop pattern), for example,

  1. Thread waits for fence value (eg. Main thread).
  2. Begin multiple threads to populate command lists.
  3. Wait all threads done with population.
  4. ExecuteCommandLists.
  5. Swap chain present.
  6. Return to 1 in the next loop.

If I am totally misunderstanding, please help.

Upvotes: 0

Views: 853

Answers (1)

Tom Huntington
Tom Huntington

Reputation: 3423

Q1. When do we need multiple command queues?

Read this https://learn.microsoft.com/en-us/windows/win32/direct3d12/user-mode-heap-synchronization:

  1. Asynchronous and low priority GPU work. This enables concurrent execution of low priority GPU work and atomic operations that enable one GPU thread to consume the results of another unsynchronized thread without blocking.
  2. High priority compute work. With background compute it is possible to interrupt 3D rendering to do a small amount of high priority compute work. The results of this work can be obtained early for additional processing on the CPU.
  3. Background compute work. A separate low priority queue for compute workloads allows an application to utilize spare GPU cycles to perform background computation without negative impact on the primary rendering (or other) tasks.
  4. Streaming and uploading data. A separate copy queue replaces the D3D11 concepts of initial data and updating resources. Although the application is responsible for more details in the Direct3D 12 model, this responsibility comes with power. The application can control how much system memory is devoted to buffering upload data. The app can choose when and how (CPU vs GPU, blocking vs non-blocking) to synchronize, and can track progress and control the amount of queued work.
  5. Increased parallelism. Applications can use deeper queues for background workloads (e.g. video decode) when they have separate queues for foreground work.

Q2. Why do we need multiple fences?

All gpu work is asynchronous. So you can think of fences as low level tools to achieve the same result as futures/coroutines. You can check if the work has been completed, wait for work to complete or set an event on completion. You need a fence whenever you need to guarantee a resource holds the output of work (when resource barriers are insufficient).

Q4. Does GetCPUDescriptorHandleForHeapStart() return value changes?

No it doesn't.

store the value for reuse, it didn't change when I debugged.

The direct3d12 samples do this, you should know them intimately if you want to become proficient.

Rendering loop in my mind is (based on Game Loop pattern), for example,

That sounds okay, but I urge you to look at the direct3d12 samples and steal the patterns (and the code) they use there.

Upvotes: 1

Related Questions