在我正在开发Android,OpenGL 3.0的应用程序中,我有一个复杂的大型对象,有大约80000-90000个顶点和数十万个三角形。此对象与许多其他明显更小且更简单的对象一起存在。
对于80000-90000个顶点,我必须使用GL_UNSIGNED_INT和IntBuffer作为索引数据,最初,我将这些参数用于drawElements()并调用drawElements()一次。对象渲染正确,但我的fps明显且显着下降。我纠正了这个问题,并且基本上将一个drawElements调用分成了6个drawElements调用,将我的IntBuffer分解为6个。所以这就是我的代码的样子:
最初:
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length, GLES30.GL_UNSIGNED_INT, indexBuffer);
我改变后:
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[0]);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[1]);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[2]);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[3]);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[4]);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length/6, GLES30.GL_UNSIGNED_INT, indexBuffers[5]);
其中indexBuffers []是一个包含我的IntBuffer的IntBuffers数组,分为6个部分。
不知何故,打破drawElements调用加快了我的应用程序,我的fps大大提高了。
为什么会这样?任何人都可以解释为什么打破电话(但仍然连续一个接一个地打电话)比拨打一个大电话更快?它与OpenGL的线程机制有关吗?
我完全没有受过教育的猜测是,制作一个drawElements调用就像开始一个新线程一样。因此,拆分调用将在一组线程之间划分工作。这是对的吗?
答案 0 :(得分:0)
您没有将VBO用于顶点数据,也不用于索引数据。
因此,简化,这意味着以下内容:每次执行glDrawElements时,所有顶点和索引数据都必须从" CPU复制到GPU" /" RAM到VRAM"在GPU可以开始绘制任何东西之前。
这"复制"在CPU端完成(由GLES驱动程序完成),一旦完成,GPU就可以开始渲染,与CPU未来处理并行。因此,当CPU正在复制时,GPU基本上是IDLE(除非它仍然忙于渲染先前的绘制调用)。当然,你拥有的顶点/索引越多,执行此操作所需的时间就越多,#34; copy"。
所以现在这就是我认为发生的事情,
当您在每个帧进行独特的绘制调用时:
当你进行6次平局调用时:
因此,通过分割6个绘制调用可以获得更好的CPU / GPU并行化,但这是因为:您没有使用VBO,并且您的场景可能不是非常复杂(就绘制调用计数和着色器循环计数而言)。 / p>
使用VBO时,此副本"不需要操作,因此事情要快得多,并且多次绘制调用中的分割应该没有性能。
PS:你可以指定你正在测试的Android设备,因为在Android"丛林和#34中至少有5个不同的GPU品牌(Adreno,Mali,Nvidia,Power VR,Vivante) ;因此,根据手机的不同,行为可能会有所不同。