OpenGL中的缓冲区绘图

时间:2013-12-29 10:29:14

标签: opengl

在这个问题中,我对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)

我们希望使用glBufferSubData将其映射到GL状态。

问题

映射时,我们必须跟踪内存中的数据,因为glBufferSubData需要startsize。这听起来像是一个分配问题:我们想要分配内存并跟踪它的位置。由于我们希望快速访问它,我们希望数据处于相同的存储位置,例如,使用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>中出现碎片。


另一方面,我们也可以为每个缓冲区设置一个块:不是将块分配给同一个缓冲区,而是将每个块(现在为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. 在此决定中需要考虑哪些要点?

1 个答案:

答案 0 :(得分:2)

目前尚不清楚是否要求进行绩效权衡。但我会用这把钥匙回答。

  
      
  1. 拥有任意数量的缓冲区是一个问题吗?
  2.   

这是一个问题来自中世纪的黑暗时期,由于向后兼容的原因,管道被修复并暂时休息。 glBind*被认为是现代OpenGL驱动程序中的(一个)性能瓶颈,由不良locality of references和缓存未命中引起。简单地说,缓存是冷的,并且CPU的大部分时间只是在驱动程序中等待从主存储器传输的数据。驱动程序实现者无法使用当前API执行任何操作。阅读Nvidia的简短article about it及其无绑定扩展提议。

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

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

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

只有一个。分析结果;) “过早优化是所有邪恶的根源”,所以尽量保持客观,只相信数字。当数字变坏时,我们可以想到:

“巨大”,“一体化”资源:

  • less bind calls
  • 减少上下文更改
  • 更难管理和调试,需要一些额外的代码基础架构(例如更新资源数据)
  • 调整大小(重新分配)非常慢

单独资源:

  • 更多绑定调用,在驱动程序中浪费时间
  • 更多背景变化
  • 更易于管理,更不容易出错
  • 易于调整大小,分配,重新分配

最后,我们可以看到在更新数据时存在性能复杂性权衡和不同行为。要坚持一种方法,你必须:

  • 决定,您是希望保持简单,易于管理或增加复杂性并获得额外的FPS(图形分析器中的配置文件以了解多少。是否值得?)
  • 知道调整缓冲区/重新分配缓冲区的频率(在图形调试器中跟踪API调用)。

希望它有所帮助;)

如果您喜欢这样的理论断言,可能您会对another one, about interleaving(DirectX one)感兴趣