Opengl es 2.0 - 为什么 glFinish 在我的新 android phone 上给我的帧率比旧的低?
Opengl es 2.0 - why does glFinish give me a lower framerate on my new android phone compared with an old one?
我最近将我的旧 Galaxy S2 phone 升级到了全新的 Galaxy S7,并且非常惊讶地发现我编写的旧游戏在新 phone 上的表现似乎更差。在将所有内容简化为一个简单的项目之后,我发现了问题 - 我在每个 onDrawFrame 结束时执行的 GLES20.glFinish() 调用。有了这个,有 glClear 但没有绘制调用,FPS 徘徊在 40 左右。没有 glFinish,稳定的 60 FPS。无论如何,我的旧 S2 都有稳定的 60 FPS。
然后我回到我的游戏,删除了 glFinish 方法调用,果然性能恢复到完美,并且没有明显的缺点。
为什么 glFinish 在我的新 phone 而不是我的旧 phone 上降低了我的帧速率?
我认为一个推测性的答案是最好的,所以——很抱歉几乎肯定会重复很多你已经知道的事情:
发送到 OpenGL 的命令经历三种状态,相对于 GPU 方面的事物命名:
- 未提交
- 已提交但待处理
- 完成
与代码通信 运行 GPU 通常很昂贵。因此,大多数 OpenGL 实现都接受您的调用,并且只是在您的内存 space 中排队等待一段时间。在某些时候,它会决定一次通信是合理的,并将支付一次转移所有呼叫的费用,将它们提升到已提交状态。然后 GPU 将完成每一个(可能乱序,前提是不破坏 API)。
glFinish
:
... does not return until the effects of all previously called GL
commands are complete. Such effects include all changes to GL state,
all changes to connection state, and all changes to the frame buffer
contents.
因此,在一段时间内 CPU 线程可能一直在做其他事情,现在肯定不会了。但是,如果您不 glFinish
那么您的输出可能仍会出现,只是不清楚何时出现。 glFlush
通常是正确的前进方式——它会提前提交所有内容,而不是等待完成,所以所有内容肯定会很快出现,您不必费心等待。
OpenGL 绑定到 OS 变化很大;一般来说,如果您的环境允许您这样做,您几乎肯定想要刷新而不是完成。如果 flush 和 finish 都无效并且 OS 没有根据任何标准为您推动事情,那么您可能会招致一些额外的延迟(例如,您发出一帧的命令可能无法到达 GPU直到你在下一帧再次填满未提交的队列)但是如果你无限期地做 GL 工作那么输出几乎肯定会继续进行。
Android 坐在 EGL 上。根据规范,3.9.3:
... eglSwapBuffers
and eglCopyBuffers
perform an implicit flush operation
on the context ...
因此,我认为如果您使用双缓冲,则不需要在 Android 中执行刷新或完成。调用交换缓冲区将在绘制完成后立即进行缓冲区交换,而不会阻塞 CPU.
至于真正的问题,S7 有一个 Adreno 530 GPU。 S2 有一个 Mali T760MP6 GPU。 Malis 是 ARM 生产的,Adrenos 是高通生产的,所以它们是完全不同的架构和驱动程序实现。所以导致阻塞的差异几乎可以是任何东西。但这是允许的。 glFinish
不是必需的,是一种非常生硬的工具;它可能不是主要的优化目标之一。
我最近将我的旧 Galaxy S2 phone 升级到了全新的 Galaxy S7,并且非常惊讶地发现我编写的旧游戏在新 phone 上的表现似乎更差。在将所有内容简化为一个简单的项目之后,我发现了问题 - 我在每个 onDrawFrame 结束时执行的 GLES20.glFinish() 调用。有了这个,有 glClear 但没有绘制调用,FPS 徘徊在 40 左右。没有 glFinish,稳定的 60 FPS。无论如何,我的旧 S2 都有稳定的 60 FPS。
然后我回到我的游戏,删除了 glFinish 方法调用,果然性能恢复到完美,并且没有明显的缺点。
为什么 glFinish 在我的新 phone 而不是我的旧 phone 上降低了我的帧速率?
我认为一个推测性的答案是最好的,所以——很抱歉几乎肯定会重复很多你已经知道的事情:
发送到 OpenGL 的命令经历三种状态,相对于 GPU 方面的事物命名:
- 未提交
- 已提交但待处理
- 完成
与代码通信 运行 GPU 通常很昂贵。因此,大多数 OpenGL 实现都接受您的调用,并且只是在您的内存 space 中排队等待一段时间。在某些时候,它会决定一次通信是合理的,并将支付一次转移所有呼叫的费用,将它们提升到已提交状态。然后 GPU 将完成每一个(可能乱序,前提是不破坏 API)。
glFinish
:
... does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.
因此,在一段时间内 CPU 线程可能一直在做其他事情,现在肯定不会了。但是,如果您不 glFinish
那么您的输出可能仍会出现,只是不清楚何时出现。 glFlush
通常是正确的前进方式——它会提前提交所有内容,而不是等待完成,所以所有内容肯定会很快出现,您不必费心等待。
OpenGL 绑定到 OS 变化很大;一般来说,如果您的环境允许您这样做,您几乎肯定想要刷新而不是完成。如果 flush 和 finish 都无效并且 OS 没有根据任何标准为您推动事情,那么您可能会招致一些额外的延迟(例如,您发出一帧的命令可能无法到达 GPU直到你在下一帧再次填满未提交的队列)但是如果你无限期地做 GL 工作那么输出几乎肯定会继续进行。
Android 坐在 EGL 上。根据规范,3.9.3:
...
eglSwapBuffers
andeglCopyBuffers
perform an implicit flush operation on the context ...
因此,我认为如果您使用双缓冲,则不需要在 Android 中执行刷新或完成。调用交换缓冲区将在绘制完成后立即进行缓冲区交换,而不会阻塞 CPU.
至于真正的问题,S7 有一个 Adreno 530 GPU。 S2 有一个 Mali T760MP6 GPU。 Malis 是 ARM 生产的,Adrenos 是高通生产的,所以它们是完全不同的架构和驱动程序实现。所以导致阻塞的差异几乎可以是任何东西。但这是允许的。 glFinish
不是必需的,是一种非常生硬的工具;它可能不是主要的优化目标之一。