Why is Android OpenGL ES rendering improved when I add a thread?

101 Views Asked by At

Before I state the question, if you want to see all the code, it is here...

https://github.com/spencerparkin/GravityMaze

(Try not to get hung up on the fact that this is an idiotic app.)

Now to the question...

My app does nothing more than draw lines of various colors. In fact, all of this is done in a single draw-call. Further, if I comment out that draw call and only clear the color buffer and swap, my rendering is still slow. My FPS counter says I'm usually at about 100 FPS, but the animation undoubtedly proves that my rendering is slow.

Fast forward a few days. I decide to punt on performance and add some MIDI music. The MIDI player does nothing but send MIDI messages to a port. The overhead it adds to the main thread is so minimal, I don't believe it can impact performance. However, what this confirmed, is that my main-loop is sluggish, because after doing this, not only was the rendering still slow (no surprise there), but the music playback was slow too, and the tempo was not constant. I commented out the rendering code again (leaving just the eglSwapBuffers() call) so that nothing rendered and the music was still slow. (No surprise there, and the slow music just confirms the main-thread sluggishness problem.)

Okay, now get this. I decide to compromise. My rendering is slow, fine, but I want the music to playback at the correct and consistent rate. So I make the effort to off-load the MIDI playback to its own thread so that it won't be effected by the slowness problem that the main-thread currently has. Well guess what?! After doing this, both my main thread and the MIDI thread now run at a reasonable frame-rate! The rendering is now as fast as I could ever want it to be! My FPS is now ~40 (lower than 100?!), but things really are rendering much, much faster. >Brain explosion!<

Does anyone know what in the world is going on here? Off-loading MIDI playback to its own thread is NOT what improved render performance. (Again, MIDI didn't exist when render performance was still slow.) It seems that the only real difference is the presents of an additional thread. Why would an additional thread cause my main thread to render OpenGL ES faster?

In my profiling, I suspected the eglSwapBuffers() call to be the bottleneck.

I'm testing on an Android 10 with API level 29, I believe.

Any ideas?

Thanks, --Spencer

1

There are 1 best solutions below

0
Spencer Parkin On

@Morrison Change pointed me to the correct answer.

I watched the video he cited to get an idea of how to better structure the program. My program is now rendering and animating at top speed. (After all, it only renders lines, so it should be blazing fast.)

Here's what I did...

  1. I created a new thread at the start of android_main() that does absolutely nothing! Seriously! It did absolutely nothing! This resulted in my render and animation performance increasing dramatically, (for an as-yet unknown reason), but I did not stop there.

  2. I moved all of my game logic into the new thread (which I'll now call the "game" thread.) This includes physics, animation, game-play logic and collision detection. Audio output, sensor input and rendering stayed in the android_main() thread, which I'll now call the "render" thread.

  3. As per the video, when my game thread goes to "render", it does nothing more than add a frame object to a thread-safe list which is consumed by the render thread. Again, from the video, I took the stratagy of having the render thread drop frames if it's too slow, or just render the same frame twice if it's too fast, in relation to the game thread.

And that's it. This seems to work really well. A caveat in all this, however, is that since this wasn't my strategy from the beginning, I have to be very weary of having inadvertently introduced threading issues. Things seem stable so far.

Thanks again.