Opengl es OpenGL优化-重复顶点流或重复调用GLD元素?

Opengl es OpenGL优化-重复顶点流或重复调用GLD元素?,opengl-es,opengl-es-2.0,Opengl Es,Opengl Es 2.0,这是针对Android上的OpenGL ES 2.0游戏,尽管我怀疑正确的答案对于任何OpenGL情况都是通用的 TL;DR-是否最好将N个数据发送到gpu一次,然后使用它进行K个draw调用;或者将K*N数据发送到gpu一次,然后进行1次抽签调用 更多详细信息我想知道适合我的情况的最佳做法。我有一个动态网格,每一帧我都会重新计算它的顶点——把它想象成一个水面——我需要在我的游戏中将这些顶点投影到K个不同的四边形上。(在每种情况下,投影都略有不同;保留细节,您可以将它们想象为围绕网格的K个不同的

这是针对Android上的OpenGL ES 2.0游戏,尽管我怀疑正确的答案对于任何OpenGL情况都是通用的

TL;DR-是否最好将N个数据发送到gpu一次,然后使用它进行K个draw调用;或者将K*N数据发送到gpu一次,然后进行1次抽签调用

更多详细信息我想知道适合我的情况的最佳做法。我有一个动态网格,每一帧我都会重新计算它的顶点——把它想象成一个水面——我需要在我的游戏中将这些顶点投影到K个不同的四边形上。(在每种情况下,投影都略有不同;保留细节,您可以将它们想象为围绕网格的K个不同的镜子。)K的数量级为10-25;我还在想办法

我可以想出两个广泛的选择:

  • 按原样绑定网格,并在不同时间调用draw K 更改着色器的统一设置或使用固定函数 状态以渲染到正确的四元体(在屏幕上)或不同的四元体 纹理的分段(稍后在渲染四边形以实现 同样的效果)

  • 将网格中的所有顶点复制K次,基本上形成一个 包含K个网格的单顶点流,并添加属性(或 指示每个网格克隆应投影的四边形 上(以及如何到达),并使用顶点着色器进行投影。我 将调用一次draw,但发送的数据是draw的K倍

  • 问题是:在这两个选项中,哪一个总体性能更好

    (另外:有没有更好的方法


    我曾考虑过第三种选择,将网格细节渲染到纹理中,并将我的K-clone几何体创建为一种虚拟流,我可以一次性绑定它,在顶点着色器中查找每个顶点的纹理,以找出它真正代表的顶点;但我被告知顶点着色中的纹理支持rs在OpenGL ES 2.0中很差或是被禁止的,并且更愿意避免这种途径。)

    这个问题没有完美的答案,尽管我建议您考虑一下实时计算机图形和OpenGL管道的本质。尽管“GL”需要产生与订单执行一致的结果,但现实是GPU是高度并行的。如果您在同一时间有许多不相关的任务(有些甚至将整个管道分割成离散的块),那么它们采用了很多技巧,效果最好。例如,GDDR内存的延迟非常高,因此为了提高效率,GPU需要能够调度其他作业,以使流处理器(着色器单元)在为刚开始的作业提取内存时保持忙碌

    如果您在每一帧重新计算网格的一部分,那么您几乎肯定希望在每一帧传输大量CPU->GPU数据的同时,支持更多的draw调用。用不必要的数据传输使总线饱和,甚至会困扰PCI Express硬件(这比几个额外的draw调用所增加的开销要慢得多),这在嵌入式OpenGL ES系统上只会变得更糟。话虽如此,您没有理由不能简单地执行
    glBufferSubData(…)
    来仅流式处理网格的受影响部分,并在单个绘制调用中继续绘制整个网格

    如果您分割(或分割)缓冲区中的数据和/或绘制调用,您可能会获得更好的缓存一致性,这取决于您的实际用例场景。要决定性地判断哪一种方法在您的情况下更有效,唯一的方法是在目标硬件上评测您的软件。但所有这些都没有从更大的角度来看,即:“我为什么要在CPU上这样做?!”
    听起来你真正想要的是顶点实例化。如果您可以通过传递实例ID来重新工作算法,使其完全在顶点着色器中工作,那么您应该会看到,与您迄今为止提出的所有解决方案相比,有了巨大的改进(真正的实例实际上介于解决方案1和2中所述的解决方案之间):)

    实例的实际概念非常简单,无论您的特定版本的OpenGL API是否在API级别支持它,都会给您带来好处(您始终可以使用顶点属性和额外的顶点缓冲区数据手动实现它)。问题是,如果您正确地实现了实例化,那么您根本不必复制数据。识别每个单独顶点所需的额外数据是静态的,您可以始终更改着色器统一并进行额外的绘制调用(这可能是您必须使用OpenGL ES 2.0进行的操作,因为它不提供
    glDrawerElementsInstanced
    ),而不接触任何顶点数据

    当然,你不必重复你的顶点K*N次,你的缓冲区空间复杂度更像O(K+K*M),其中M是你必须添加的新组件的数量,以唯一地标识每个顶点,这样你就可以计算GPU上的所有内容。例如,您可能需要为四边形1-4中的每个顶点编号,并根据正在处理的顶点在着色器中以不同方式处理顶点。在这种情况下,M系数为1,无论需要动态计算每个帧的四边形实例有多少,它都不会改变;N将决定OpenGL ES 2.0中绘制调用的数量,而不是数据的大小。如果OpenGL ES 2.0支持gl_VertexID:(

    实例化是有效利用高度并行GPU并避免CPU/GPU同步和缓慢总线传输的最佳方法。尽管OpenGL ES 2.0不支持API意义上的实例化,但使用相同顶点缓冲区的多个绘图调用在调用之间更改的唯一内容是