Sunday, 21 August 2011

OpenGL Line Drawing is Broken on Some Android Phones

Drawdle is a somewhat performance-intensive application, both because of its physics engine and its graphics (crude as they are). On older devices, such as the HTC hero, it is advisable to turn the background off for a smoother performance, as the objects floating around back there account for a significant amount of rendering time. In fact, Drawdle automatically disables the background on devices that have a resolution smaller than 800x480 on the basis that such devices are probably older or otherwise less powerful, and we want to ensure good performance "out of the box" on as many devices as possible.




Drawdle with the backgrounds on
That said, I had been getting reports of very poor performance from users with new, high-powered devices such as the HTC Thunderbolt, Desire HD and Incredible 2. And not poor as in 15-20 FPS (as with my Hero when backgrounds are on), but as bad as 1-2 FPS, not even remotely playable. These users made their displeasure very clear on the Drawdle Lite ratings/comments board on the Android Market.

Why was this happening? Drawdle plays great, background and all, on my friend's HTC Evo 4G, a device that is similar to the HTC Thunderbolt only a year older and by any measure not as powerful. The story was the same for the Droid Incredible line of phones: Drawdle plays fine on the original and plays horribly on the newer model. Something was very wrong.

The culprit, as I was able to verify, was the background. Users who turned the Drawdle background off on their Thunderbolts reported markedly improved performance, in line with devices that were known to be OK. Unfortunately, this was not enough to go on: the code responsible for the background in Drawdle wasn't that different from the rest of the codebase. Creating the background required the physics engine, line rendering and buffer updating, nothing that that wasn't being done all the time anyway.

I didn't have access to an affected device to profile on (an a la carte Thunderbolt costs $700 retail), so tracking this down would not be quick. I started by converting my vertex arrays to VBOs, confident that there was a bug in the glDrawArrays implementation on these devices. A quick trip to the Verizon Store to test my fix showed that my optimism was misplaced, as there was no improvement. This pattern repeated itself when I tried disabling the physics engine and updates to the color buffers for the background objects (look closely and you can see the objects periodically change their colors). Nothing that I tried helped.

My only hint was this post discussing a similar problem on a weather application: some users were reporting that the app ran fine on their devices until they turned on county lines. I had an epiphany that night while thinking about that post: it was line drawing that was slowing my app on these devices, sprite rendering, which was implemented the same way, using glDrawArrays, worked fine.

I set about converting my line drawing calls to their equivalent triangle strip calls. This wasn't trivial or cheap (a triangle strip requires twice as many vertices as an equivalent line, line strip or line loop), but it was worth the effort. On my next round of testing (thank you Verizon Store) my app performed flawlessly.

Long story short, you should avoid drawing calls with GL_LINES, GL_LINE_STRIP and GL_LINE_LOOP when developing for Android. This goes for both vertex arrays and VBOs. This problem appears to affect only some phones with Adreno 205 GPUs, but that isn't proven at this point. More research is needed; if you have anything to share, please drop me a line or leave a comment here.

No comments:

Post a Comment