此外,交错与非交错顶点缓冲区之间是否存在性能问题?谢谢!
有几种方式。我将描述最简单的一种。
只需创建单独的顶点缓冲区:
ID3D11Buffer* positions;
ID3D11Buffer* texcoords;
ID3D11Buffer* normals;
创建输入布局元素,每个组件都逐个增加 InputSlot
成员:
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 2, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
// ^
// InputSlot
将缓冲区绑定到它们的插槽(最好一次性全部完成):
ID3D11Buffer** vbs = {positions, texcoords, normals};
unsigned int strides[] = { /*strides go here*/ };
unsigned int offsets [] = { /*offsets go here*/ };
m_Context->IASetVertexBuffers(0, 3, vbs, strides, offsets );
按照惯例进行绘制。 您不需要更改HLSL代码(HLSL将认为它只有单个缓冲区)。
请注意,代码片段是即时编写的,可能包含错误。
编辑:您可以通过更新率组合缓冲区来改进此方法:如果texcoords
和normals
从未更改,请合并它们。
这完全取决于引用局部性:数据越接近,访问速度越快。
在大多数情况下,交错缓冲区对GPU端(即渲染)性能的提升要大得多:每个顶点的每个属性都靠近彼此。但是,单独的缓冲区可以更快地访问CPU:数组是连续的,每个下一个数据都靠近前一个。
因此,总体而言,性能问题取决于您多频繁写入缓冲区。如果您的限制因素是CPU写入,则应使用单独的缓冲区。否则,使用交错缓冲区。
如何知道?唯一的方法是分析。无论是CPU还是GPU端(通过您GPU供应商的图形调试器/分析器)。
最佳实践是限制CPU写入,因此,如果您发现受到缓冲区更新的限制,您可能需要重新审视自己的方法。如果我们每秒有500帧,我们是否需要在每个帧更新时都更新缓冲区?如果您将缓冲区更新速率降至30-60次每秒,则用户不会看到任何区别(将缓冲区更新与帧更新解绑)。因此,如果您的更新策略合理,则很可能永远不会受到CPU限制,最佳方法是经典的交错。
您还可以考虑重新设计数据流程,甚至某种方式的离线准备数据(我们称之为“烘焙”),以便您无需处理非交错的缓冲区。这也是相当合理的。
内存和性能之间的平衡取舍。这是永恒的问题。复制内存以利用交错的优势?或者干脆不这样做呢?
答案是...“那要看情况”。您正在编写面向配备了数GB内存的顶级GPU的CryEngine新版本?还是您正在为内存资源受限且缓慢的嵌入式系统或移动平台编程?1 MB的内存是否真的值得麻烦?或者您有巨大的模型,每个模型100 MB?我们不知道。
决定权在于您。但请记住:没有免费的糖果。如果您发现内存经济效益超过性能损失,请这样做。进行分析和比较以确保。
希望它在某种程度上能帮助您。愉快的编码!=)
Interleaved/Separate主要影响您的输入装配阶段(GPU端)。
当您的缓冲区内存排列完全符合顶点着色器输入时,交错是一个完美的场景。因此,您的输入装配程序可以简单地获取数据。
在这种情况下,即使使用大型模型进行测试(相同数据的两个版本,一个交错,一个分离),时间戳查询也没有报告任何重大差异(一些非常小的顶点处理和基本像素着色器)。
现在,如果使用单独的缓冲区,则更容易对其进行微调,以便在不同上下文中使用几何图形。
假设您有位置/法线/UV(就像您的情况一样)。
现在,您的管道中还有一个仅需要位置的着色器(Shadow Map将是一个很好的例子)。
使用单独的缓冲区,您可以简单地创建一个新的输入布局,其中仅包含位置,并绑定该缓冲区。您的IA阶段只需加载该缓冲区。最重要的是,您甚至可以使用着色器反射动态执行此操作。
如果绑定交错数据,则由于必须使用步幅进行加载,会产生一些开销。
当我测试时,使用分离而不是交错获得了约20%的增益,这可能相当不错,但由于此类处理在很大程度上取决于架构,请勿将其视为理所当然(NVidia 740M用于测试)。
因此,简单地说,要进行大量分析,并检查哪种方法可以在GPU和CPU负载之间实现最佳平衡。
还请注意,如果应用一些重型计算+添加一些镶嵌+一些体面的着色,输入装配程序的开销将随着着色器的复杂性而减少,交错/非交错之间的时间差异将逐渐变得无意义。