缓冲区 - 索引或直接,隔行扫描或分离

时间:2013-07-06 14:17:28

标签: opengl

选择顶点缓冲区类型有哪些常用指南?我们什么时候应该使用隔行扫描缓冲区来处理顶点数据?我们什么时候应该使用索引数组和直接顶点数据?

我正在寻找一些常见的quidelines - 在某些情况下,其中一个或相反的更适合,但并非所有情况都很容易解决。在针对性能时,应该考虑选择顶点缓冲区格式?

也欢迎链接到该主题的网络资源。

2 个答案:

答案 0 :(得分:16)

首先,您可以在OpenGL维基上找到一些useful information。其次,如果有疑问,可以对这个有一些经验法则,但经验可能因数据集,硬件,驱动程序......而异。

索引与直接渲染

我几乎总是默认使用顶点缓冲区的索引方法。主要原因是所谓的post-transform cache。它是在图形管道的顶点处理阶段之后保留的缓存。本质上,它意味着如果您多次使用顶点,则很有可能达到此缓存并且能够跳过顶点计算。有一个条件甚至可以命中这个缓存,那就是你需要使用索引缓冲区,没有它们就无法工作,因为索引是这个缓存密钥的一部分。

此外,您可能会节省存储空间,索引可以尽可能小(1个字节,2个字节),您可以重用完整的顶点规范。假设一个顶点和所有属性总共约30个字节的数据,你可以分享这个顶点,比如2个多边形。使用索引渲染(2字节索引),这将花费您2*index_size+attribute_size = 34 byte。使用非索引渲染,这将花费您60个字节。通常,您的顶点将被共享两次以上。

基于索引的渲染总是更好吗?不,可能会出现情况更糟的情况。对于非常简单的应用程序,设置基于索引的数据模型可能不值得代码开销。此外,当您的属性不是通过多边形共享时(例如,正常的每个多边形而不是每个顶点),可能根本没有顶点共享,IBO不会带来好处,只是开销。

接下来,虽然它启用了转换后缓存,但它确实使通用内存缓存性能更差。因为你相对随机地访问属性,你可能会有更多的缓存未命中和内存预取(如果这将在GPU上完成)将无法正常工作。因此,如果你有足够的内存并且你的顶点着色器非常简单,非索引版本优于索引版本,那么可能(但是衡量)。

交织与非交错与每个属性的缓冲区

这个故事有点微妙,我认为它归结为称量属性的某些属性。

  1. Interleaved可能会更好,因为所有属性都会靠近在一起,并且可能在几个内存缓存行中(甚至可能只有一个)。显然,这可能意味着更好的表现。但是,结合基于索引的渲染,无论如何,您的内存访问都是随机的,其好处可能比您预期的要小。
  2. 了解哪些属性是静态的,哪些是动态的。如果您有5个属性,其中2个是完全静态的,1个每15分钟更改一次,每10秒更换2个,请考虑将它们放在2个或3个单独的缓冲区中。每次最常更换2次时,您不希望重新上传所有5个属性。
  3. 考虑属性应该在4个字节上对齐。因此,您可能希望不时地进行交错甚至更进一步。假设你有一个vec3 1字节属性和一些标量1字节属性,天真地需要8个字节。通过将它们放在一个vec4中可以获得很多收益,这可以将使用量减少到4个字节。
  4. 使用缓冲区大小,过大的缓冲区或过多的小缓冲区可能会影响性能。但这可能非常依赖于硬件,驱动程序和OpenGL实现。

答案 1 :(得分:4)

索引与直接

让我们通过索引看看你得到了什么。每个重复的顶点,即具有“平滑”中断的顶点将花费更少。每个单一的“边缘”顶点都会花费更多。对于基于现实世界并且相对密集的数据,一个顶点将属于许多三角形,因此索引将加速它。对于程序生成的任意数据,直接模式通常会更好。

索引缓冲区还会给代码增加额外的复杂性。

Interleaved vs Separate

这里的主要区别实际上是基于一个问题“我只想更新一个组件吗?”。如果答案是,那么您不应该交错,因为任何更新都将非常昂贵。如果它是,使用交错缓冲区应该可以改善参考的局部性,并且通常在大多数硬件上都会更快。