【问题标题】:Multithreading in DirectX 12DirectX 12 中的多线程
【发布时间】:2016-12-09 10:44:03
【问题描述】:

我很难接受 DX12 中的多线程渲染概念。

根据 MSDN,必须将绘图命令写入 直接命令列表(最好使用捆绑包),然后将这些列表提交到 命令队列。 也有人说直接命令列表可以有多个命令队列。但我不清楚这样做的目的是什么。

我通过在并行线程中构建命令列表来充分利用多线程,不是吗?如果是这样,我为什么要与设备关联多个命令队列?

我怀疑命令队列管理不当会导致渲染库开发后期的性能出现巨大问题。

【问题讨论】:

  • msdn 提到队列可以并行执行。所以理论上使用多个队列是有好处的。但据我所知,这里没有支持并行执行的 gpu(认为 AMD 可以并行执行图形和计算队列)。

标签: multithreading directx-12


【解决方案1】:

directx 12 的主要好处是命令的执行几乎是完全异步的。这意味着当您调用ID3D12CommandQueue::ExecuteCommandLists 时,它将启动传入的命令的工作。然而,这带来了另一点。一个常见的误解是渲染现在以某种方式是多线程的,而这根本不是真的。所有工作仍然在 GPU 上执行。然而,命令列表记录是在多个线程上完成的,因为您将为每个需要它的线程创建一个 ID3D12GraphicsCommandList 对象。

一个例子:

DrawObject DrawObjects[10];
ID3D12CommandQueue* GCommandQueue = ...

void RenderThread1()
{
     ID3D12GraphicsCommandList* clForThread1 = ...
     for (int i = 0; i < 5; i++)
         clForThread1->RecordDraw(DrawObjects[i]);
}

void RenderThread2()
{
     ID3D12GraphicsCommandList* clForThread2 = ...
     for (int i = 5; i < 10; i++)
         clForThread2->RecordDraw(DrawObjects[i]);
}

void ExecuteCommands()
{
     ID3D12GraphicsCommandList* cl[2] = { clForThread1, clForThread2 };
     GCommandQueue->ExecuteCommandLists(2, cl);
     GCommandQueue->Signal(...)
}

这个例子是一个非常粗略的用例,但这是大意。您可以在不同的线程上记录场景的对象,以消除记录命令的 CPU 开销。

另一个有用的事情是,通过此设置,您可以启动渲染任务并开始录制另一个任务。

一个例子

void Render()
{
     ID3D12GraphicsCommandList* cl = ...
     cl->DrawObjectsInTheScene(...);
     CommandQueue->Execute(cl); // Just send it to the gpu to start rendering all the objects in the scene

     // And since we have started the gpu work on rendering the scene, we can move to render our post processing while the scene is being rendered on the gpu
     ID3D12GraphicsCommandList* cl2 = ...
     cl2->SetBloomPipelineState(...);
     cl2->SetResources(...);
     cl2->DrawOnScreenQuad();
}

与 directx 11 或 opengl 相比,这里的优势在于这些 api 可能只是坐在那里进行记录和记录,并且可能在调用 Present() 之前不会发送它们的命令,这会迫使 cpu 等待,并产生开销.

【讨论】:

  • 谢谢!但问题仍然是:拥有多个命令队列的目的是什么?
  • 您希望有专门用于每个任务的命令队列。因此,使用 D3D12_COMMAND_QUEUE_TYPE_COPY 制作的命令队列将处理复制操作、UpdateSubresources(..)、从上传堆复制等。直接命令队列通常仅用于您的主要渲染任务,而计算队列用于您的计算任务。虽然您可以拥有多个相同类型的命令队列,但它只会让同步和资源管理变得很痛苦
  • 所以这里只是为了简化并发作业提交(通过某种内部同步),并且对于所有类型的作业具有多个命令队列与一个命令队列在其他方面没有任何区别,比如资源管理和执行速度?
  • 嗯,他们的主要方面是使用计算队列和直接队列,您可能会在 gpu 上异步执行任务。但是它们的工作原理是它们本质上暴露了硬件的不同部分,计算队列暴露了 cuda 核心,直接队列暴露了光栅化方面,复制队列暴露了 gpu 的复制部分,等等。
猜你喜欢
  • 2022-07-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 2016-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多