OpenGL状态冗余消除树,呈现状态优先级

OpenGL状态冗余消除树,呈现状态优先级,opengl,opengl-es,rendering,directx-11,batching,Opengl,Opengl Es,Rendering,Directx 11,Batching,我正在我的游戏引擎中开发一种自动OpenGL批处理方法,以减少绘制调用和冗余调用 我的批处理树设计从最昂贵的状态开始,并为每个较便宜的状态添加向下的叶子 例如: 树根:着色器/程序 兄弟:混合状态。。。 a、 s.o 因此,我的问题是,在以下列表中,最有可能最昂贵的电话是什么: 绑定程序 绑定纹理 绑定缓冲区 缓冲纹理、顶点数据 绑定渲染目标 glEnable/glDisable 混合状态方程,颜色,函数,colorWriteMask 深度模具状态depthFunc、模具操作、模具函数、Wri

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

我的批处理树设计从最昂贵的状态开始,并为每个较便宜的状态添加向下的叶子

例如: 树根:着色器/程序 兄弟:混合状态。。。 a、 s.o

因此,我的问题是,在以下列表中,最有可能最昂贵的电话是什么:

  • 绑定程序
  • 绑定纹理
  • 绑定缓冲区
  • 缓冲纹理、顶点数据
  • 绑定渲染目标
  • glEnable/glDisable
  • 混合状态方程,颜色,函数,colorWriteMask
  • 深度模具状态depthFunc、模具操作、模具函数、WriteMaks
还想知道哪种方法更快:
-将所有可批处理的绘图命令收集到单个顶点缓冲区,并仅调用1个绘图调用(此方法还将强制更新cpu端每个顶点的矩阵变换)
-根本不批处理并渲染许多小绘图调用,只批处理粒子系统…

PS:渲染目标将始终在更改之前或之后进行更改,具体取决于使用情况

迄今为止的进展:

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

N:顶点数组绑定,统一绑定

WebGL中的当前执行树:

  • 节目
  • 属性指针
  • 质地
  • 混合状态
  • 深度状态
  • 模具前/后状态
  • 光栅化状态
  • 采样器状态
  • 绑定缓冲区
  • 绘制数组
每个步骤都是一个同级哈希树,以避免在主渲染队列中再次检查状态缓存

加载纹理/程序/着色器/缓冲区发生在渲染到额外队列之前,用于将来的多线程,并且确保在使用上下文执行任何操作之前初始化上下文


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

这些操作的相对成本当然取决于使用模式和您的一般场景。但你可能会发现这是一个有用的指南。让我在这里复制幻灯片48:

状态变化的相对成本

  • 在降低成本方面
  • 渲染目标~60K/s
  • 程序约300K/s
  • 翻滚
  • 纹理绑定~1.5M/s
  • 顶点格式
  • UBO绑定
  • 统一更新速度~10M/s

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

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

尽管有这些警告:

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

  • 一般来说,更新纹理或缓冲区数据是不可能的。这显然在很大程度上取决于更新了多少数据。与internet上的一些声明相反,像
    glBufferSubData()
    glTexSubImage2D()
    这样的调用通常不会导致同步。但它们涉及数据拷贝

  • 绑定程序不应该非常昂贵,但通常比下面的状态更改更为重要

  • 纹理绑定通常比较便宜。但这要视情况而定。例如,如果使用具有VRAM的GPU,而纹理此时不在VRAM中,则可能会触发纹理数据从系统内存复制到VRAM

  • 统一更新。在某些平台上,这应该是非常快的。但在其他人身上,它实际上是相当昂贵的。所以这里有很多变化

  • 顶点状态设置(包括VBO和VAO绑定)通常很快。这是必须的,因为大多数应用程序都经常这样做,很快就会成为瓶颈。但对于纹理也有类似的考虑,如果最近没有使用缓冲区内存,则可能必须复制/映射缓冲区内存

  • 常规状态更新(如混合状态、模具状态或写入掩码)通常非常快。但也可能有很多例外


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

您的目标GL版本是什么?您的列表缺少渲染目标(FBO)状态更改,这非常昂贵(但不一定是问题)