6

我正在我的游戏引擎中使用自动 OpenGL 批处理方法,以减少绘制调用和冗余调用。

我的批处理树设计从最昂贵的状态开始,并为每个成本较低的状态添加叶子。

示例:树根:着色器/程序 兄弟:混合状态 ... aso

所以我的问题是最有可能是最昂贵的电话,在这个列表中:

  • 绑定程序
  • 结合纹理
  • 绑定缓冲区
  • 缓冲纹理、顶点数据
  • 绑定渲染目标
  • glEnable / glDisable
  • 混合状态方程、颜色、函数、colorWriteMask
  • 深度模板状态 depthFunc, stencilOperations, stencilFunction, writeMasks

还想知道哪种方法会更快:
- 将所有可批处理的绘制命令收集到单个顶点缓冲区并仅调用 1 个绘制调用(此方法还将强制在 cpu 端更新每个顶点的矩阵变换)
- 根本不进行批处理并渲染许多小绘制调用,只有批处理粒子系统...

PS:根据使用情况,渲染目标将始终更改为 Pre 或 Post。

目前进展:

  • Andon M. Coleman:最便宜的统一和顶点数组绑定、昂贵的 FBO、纹理绑定
  • datenwolf:程序使状态缓存无效

1:Framebuffer states
2:Program
3:Texture Binding
...
N:Vertex Array binding,Uniform binding

WebGL 中的当前执行树:

  • 程序
  • 属性指针
  • 质地
  • 混合状态
  • 深度状态
  • 模板正面/背面状态
  • 光栅化器状态
  • 采样器状态
  • 绑定缓冲区
  • 绘制数组

每个步骤都是一个兄弟哈希树,以避免再次检查主渲染队列中的状态缓存

加载纹理/程序/着色器/缓冲区在渲染之前发生在额外的队列中,以用于未来的多线程,并确保在对其进行任何操作之前初始化上下文。

自渲染对象的最大问题是您无法控制何时发生某些事情,例如如果开发人员在 gl 初始化之前调用这些方法,他不会知道为什么但他会遇到一些错误或问题......

4

2 回答 2

7

此类操作的相对成本当然取决于使用模式和您的一般情况。但是您可能会发现Nvidia 的“Beoynd Porting”演示幻灯片作为有用的指南。让我在这里特别复制第 48 张幻灯片:

状态变化的相对成本

  • 在降低成本...
  • 渲染目标 ~60K/s
  • 程序 ~300K/s
  • 机械手
  • 纹理绑定 ~1.5M/s
  • 顶点格式
  • UBO 绑定
  • 统一更新 ~10M/s

这并不直接匹配您列表中的所有要点。例如glEnable/glDisable,可能会影响任何事情。GL 的缓冲区绑定也不是 GPU 直接看到的。当然,缓冲区绑定主要是客户端状态,具体取决于目标。混合状态的变化将是一个 ROP 状态变化,依此类推。

于 2014-08-26T16:36:08.537 回答
0

这往往高度依赖于平台/供应商。您可能找到的任何数字都适用于特定的 GPU、平台和驱动程序版本。互联网上有很多关于这个话题的神话。如果你真的想知道,你需要编写一些基准,并在一系列平台上运行它们。

所有这些警告:

  • 渲染目标 (FBO) 切换往往非常昂贵。但是,高度依赖于平台和架构。例如,如果您有某种形式的基于 tile 的架构,那么理想情况下会延迟到帧结束的未决渲染可能必须完成并刷新。或者在更“经典”的架构上,可能存在压缩颜色缓冲区或用于早期深度测试的缓冲区,在切换渲染目标时需要考虑这些缓冲区。

  • 一般而言,更新纹理或缓冲区数据是不可能评估的。显然,这在很大程度上取决于更新了多少数据。与互联网上的一些说法相反,呼叫喜欢glBufferSubData()并且glTexSubImage2D()通常不会导致同步。但它们涉及数据副本。

  • 绑定程序不应该非常昂贵,但通常仍然比下面的状态更改更重量级。

  • 纹理绑定大多相对便宜。但这真的取决于具体情况。例如,如果您使用具有 VRAM 的 GPU,而此时纹理不在 VRAM 中,则可能会触发将纹理数据从系统内存复制到 VRAM。

  • 统一更新。据说这在某些平台上非常快。但实际上对其他人来说价格适中。所以这里有很多可变性。

  • 顶点状态设置(包括 VBO 和 VAO 绑定)通常很快。必须如此,因为大多数应用程序如此频繁地执行此操作,以至于它很快就会成为瓶颈。但是对于纹理也有类似的考虑,如果最近没有使用缓冲存储器,则可能必须复制/映射它。

  • 一般状态更新,如混合状态、模板状态或写入掩码,通常非常快。但也可能有非常大的例外。

只是一个典型的例子,说明为什么架构之间的特性会如此不同:如果你改变混合状态,那可能会在一个架构上发送几个命令字,而开销最小。在其他架构上,混合是作为片段着色器的一部分完成的。因此,如果您更改混合状态,则必须修改着色器程序以修补代码以进行新的混合计算。

于 2014-08-27T06:38:47.783 回答