哪些DirectX11调用实际上将数据发送到GPU?

我正在学习graphics编程和DirectX11。

我正在努力学习如何最大限度地减lessCPU-GPU传输和graphics编程。
我有一个问题,我一直无法从在线资源回答自己:

哪个D3D方法实际上将数据发送给GPU(对于静态网格来说,哪一个顶点数据每帧都会传递给GPU,或者只有一次)?

代码如下:
(简化为stackexchange)

在我的“mesh”类中,我有一个顶点缓冲区:

ID3D11Buffer *m_pVBuffer; 

在我的网格的构造函数中,我设置了一些顶点到顶点缓冲区:

 D3D11_MAPPED_SUBRESOURCE ms; devcon->Map(m_pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); memcpy(ms.pData, &vertices[0], sizeof(VERTEX) * vertices.size()); devcon->Unmap(m_pVBuffer, NULL); 

然后在我的网格的“渲染”方法中,我这样做:

 UINT stride = sizeof(VERTEX); UINT offset = 0; devcon->IASetVertexBuffers(0, 1, &m_pVBuffer, &stride, &offset); devcon->IASetIndexBuffer(m_pIBuffer, DXGI_FORMAT_R32_UINT, 0); devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); devcon->DrawIndexed(m_num_indices, 0, 0); 

重复一次:当我调用IASetVertexBuffers时,数据是上传到GPU,Memcpy和Unmap顶点缓冲区,还是上传到每一帧?

这是一个棘手的问题,因为您不能完全控制是否将顶点缓冲区存储在VRAM或主RAM中。 驱动程序根据创建顶点缓冲区时指定的使用情况和CPU访问标志来为您做出决定。

一般来说,具有默认和不可变用途的缓冲区将被存储在VRAM中; 那些使用阶段将被存储在主RAM中; 那些dynamic的使用可能在任何地方。 但是,如果VRAM不足,则驱动程序将在主RAM中存储资源作为回退。

如果缓冲区在VRAM中结束,则每当CPU更新缓冲区(即,执行Map / Unmap对)时,数据都会通过系统总线(连接CPU和GPU)。 如果它位于主RAM中,则每次使用该缓冲区进行渲染时,GPU将通过系统总线读取数据。

因此,对于静态网格物体,通常使用不可变的用法,缓冲区将存储在VRAM中,因此在初始设置之后不会有额外的系统总线传输。 对于一个dynamic的顶点缓冲区(粒子或类似的),你可以使用dynamic的使用方式,并且数据每一帧都会经过总线 – 如果是在VRAM中,总线将被CPU用来写入,如果它在主RAM中,总线将被用于GPU读取它。

答案将取决于任何一代高度优化的硬件驱动程序感觉如何,也就是说,没有一般的答案。

除此之外,驱动程序正在渲染1-N帧,因为3D卡是高度序列化的,并行和caching的,并且asynchronous工作以完成任务。

如果你只是在学习,那么要知道的重要信息是序列指向准备渲染:描述数据,复制数据,告诉驱动程序使用什么数据,然后触发渲染。 而不是什么时候发生,那确实是一个非常深的兔子洞。

我的理解大部分是基于这样的理解:驱动程序通常不会将任何资源发送到video内存,直到资源用于绘制调用。

这意味着构造函数可能根本不会触及GPU硬件,渲染方法将会如此。 然而,即使DrawIndexed()调用可能也不会立即使用硬件,因为缓冲大型GPU命令列表的CPU效率更高。

驱动程序也可以从GPU内存中卸载数据(假设它在主RAM中有副本)。 在极端情况下,每帧可能会发生一次以上。

当然,所有这一切都是司机对程序员隐藏的,所以你不能依赖于这样的情况 – 司机总是在变。