OpenGL中的缓冲绘图

豪尔赫·雷涛(Jorge Leitao)

在这个问题中,我对OpenGL中的缓冲区绘制感兴趣,特别是在对每个数据集使用一个缓冲区与对一个以上数据集使用一个缓冲区的权衡中。

语境:

考虑由N个顶点组成的数据集,每个顶点由一组属性(例如颜色,纹理,法线)表示。每个属性均由类型(例如GLfloat,GLint)和多个组件(2、3、4)表示。我们要绘制此数据。示意地,

(non-interleaved representation)

   data set
<-------------->
 a_1  a_2   a_3
<---><---><---->
a_i = attribute; e.g. a2 = (3 GLfloats representing color, thus 3*N Glfloats)

我们想使用将其映射到GL状态glBufferSubData

问题

映射时,我们必须跟踪内存中的数据,因为glBufferSubData需要使用startand size对我来说,这听起来像一个分配问题:我们要分配内存并跟踪其位置。由于我们想快速访问它,因此我们希望数据位于相同的存储位置,例如使用std::vector<char>示意地,

  data set 1    data set 2
<------------><-------------->
(both have same buffer id)

我们将gl状态声明为:

// id is binded to one std::vector<char>, "data".
glBindBuffer(target, id);

// for each data_set (AFTER calling glBindBuffer).

// for each attribute

// "start": the start point of the attribute.
// "size":  (sizeof*components of the attribute)*N.
glBufferSubData(target, start, size, &(data[0]))

(non non-interleaved for the sake of the code).

当我们要添加或删除顶点时,例如当LOD更改时,就会出现问题。因为每个数据集都必须是一个块,例如,以便允许交错绘制(即使在非交错状态下,每个属性也是一个块),所以我们最终会产生碎片std::vector<char>


另一方面,我们还可以为每个缓冲区设置一个块:我们可以将每个卡盘(现在为a)分配给不同的缓冲区,而不是将块分配给相同的std::vector<char>缓冲区。示意地,

  data set 1 (buffer id1)
<------------>
  data set 2 (buffer id2)
<-------------->

我们将数据提交到gl状态为:

// for each data_set (BEFORE calling glBindBuffer).
// "data" is the std::vector<char> of this data_set.

// id is now binded to the specific std::vector<char>
glBindBuffer(target, id);

// for each attribute

// "start": the start point of the attribute.
// "size":  (sizeof*components of the attribute)*N.
glBufferSubData(target, start, size, &(data[0]))

问题

我正在学习此内容,因此,在以下任何一项之前:此推理正确吗?

假设是,

  1. 拥有任意数量的缓冲区是否有问题?
  2. 预计“ glBindBuffer”会随着缓冲区的数量扩展吗?
  3. 在此决定中要考虑哪些要点?
Ivan Aksamentov-掉落

您是否询问性能权衡尚不清楚。但是我会用这个键回答。

  1. 拥有任意数量的缓冲区是否有问题?

这是一个来自中世纪的黑暗时代的问题,当时由于向后兼容的原因,管道已经固定并暂时搁置。glBind*在现代OpenGL驱动程序中,它被视为性能瓶颈(之一),这是由于引用的局部性不好和缓存未命中所引起的。简而言之,缓存很冷,并且很大一部分时间CPU仅在驱动程序中等待从主内存传输的数据。驱动程序实现者无法使用当前API进行任何操作。阅读有关Nvidia的简短文章及其无限制扩展建议。

2. Is "glBindBuffer" expected to scale with the number of buffers?

当然,更多的对象(在您的情况下为缓冲区),更多的绑定调用,驱动程序中更多的性能损失。但是合并后,庞大的资源对象难以管理。

3. What are the major points to take into consideration in this decision?

只有一个。分析结果;)“过早的优化是万恶之源”,因此,请尽可能保持客观性,并只相信数字。当数字变坏时,我们可以想到:

“巨大”,“多合一”资源:

  • 较少绑定的呼叫
  • 较少的上下文变化
  • 难以管理和调试,需要一些其他代码基础结构(例如,更新资源数据)
  • 调整大小(重新分配)非常慢

单独的资源:

  • 更多绑定呼叫,导致驱动程序浪费时间
  • 更多上下文更改
  • 易于管理,不易出错
  • 易于调整大小,分配,重新分配

最后,我们可以看到在更新数据时会有性能复杂性的折衷和不同的行为。要坚持一种方法,您必须:

  • 决定,是要使事情简单,易于管理还是要增加复杂性并获得额外的FPS(图形探查器中的探查器知道多少?是否值得?)
  • 知道您调整缓冲区大小/重新分配的频率(在图形调试器中跟踪API调用)。

希望它能有所帮助;)

如果您喜欢这样的理论断言,那么您可能会对另一种有关交织(DirectX的断言)感兴趣。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章