Since I have a 30 frames per second goal for the iPad 1 and I sometimes get only around 25 frames, I started the OpenGL profiler for the WOT project…
The OpenGL profiler in XCode Instruments is quite a nice tool. It records all OpenGL calls and sorts them for performance optimization possibilities. This is a very convenient way to find:
- redundant API calls
- render calls where you should have used indexed rendering
- render calls where you should have used interleaving
- unnecessary state query calls
Instruments shows you what call is redundant and a stack trace to the invocation in your code. At this point you should know, that redundant OpenGL calls can hurt performance and you should avoid unnecessary OpenGL state changes.
And here comes the scary thing! Almost all redundant OpenGL calls are not from my code but from GLKit. There is for instance every frame a call to glViewport(), even when it does not change. But that is not the serious performance killer. Every time you bind a shader via GLKBaseEffect you get a ton of redundant API calls to OpenGL.
To name a few, there is every time a call to glActiveTexture(), glBindTexture(), glVertexAttrib4fv() and a lot of calls to glUniform4fv().
But this is not Apple’s fault. It is just the fact, that if you want to reduce redundant OpenGL calls, you have to track the OpenGL state and decide if your call would be unnecessary. GLKit is not a engine and therefore cannot track the OpenGL state.
The conclusion is simple. I have to build shader management into the Nice3D engine and kick GLKBaseEffect out. That way the engine gains control over the state changes involved in shader apply and can easily sort out redundant API calls. This would also solve a problem that I have in memory management (see First Memory Profiling).
Note to myself: Nice3D shader management is desperately required. Not only for the above performance issues but also for skeletal animation and nice terrain rendering.