Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding stalls while uploading textures on Android

Our game requires us to constantly load and create new images which we put onto a texture page then use to render. We upload using glTexSubImage2d to modify part of the texture page. We dont keep a system copy. Whenever we do this we have a six frame delay inside the glTexSubImage2d call. We do load most of our images onto textures before the game starts, but some things are necessarily dynamic.

I assume the entire rendering pipeline, be it double or triple buffered is being flushed because I want to modify a texture that it is using, or has a reference to. Even so, six frames plus (0.1 seconds) seems excessive. We do exactly the same on IOS and you barely notice any delay when a texture has been modified. The game normally runs on 1 or 2 frames.

Anyone got any idea what is going on ? This is running on a Samsung Galaxy Note GTN7000. We're using the SurfaceView class. Can you "turn this stall off". I understand this may mean artefacts for a frame or so where the render may not have the updated texture.

Furthermore, any idea how to know or set whether internally its being double or triple buffered.

I've also read that most Desktop/PC OpenGL drivers get round this by having two or three copies of the textures and updating only those that aren't currently being used, then updating the copies in good time. We simply don't have the memory for that!

Thanks

Shaun

like image 667
user3162134 Avatar asked Jan 05 '14 08:01

user3162134


1 Answers

The Mali GPU (used in the N7000) is the worst GPU for this kind of texture upload stall. Other GPUs handle it much better (or at least the drivers handle it better).

I've experienced the exact same problem you describe, and the only solution for me was to keep a CPU copy of the texture data, and to triple buffer the texture. Whenever I modify the texture, I modify the CPU copy only, and mark the textures as being dirty. At the start of each frame, if the buffer has been updated, I cycle the three textures and do glTexSubImage2D on one of them, which then becomes the active texture.

If you use less than three textures, or if you make any mistakes and have used the texture you did glTexSubImage2D on within the last two frames, it will still stall.

I only do this when I detect a Mali GPU (check the driver GL string). For other GPUs and for iOS, the drivers are good enough that triple buffering is not required (and so I don't have to keep the CPU copy of the data either). I did check on the Arm/Mali developer forums about this issue, and they recommended triple buffering. You should not need more than three though.

Another workaround I had some limited success with was to always use glTexImage2D instead of glTexSubImage2D on Mali GPUs. This required keeping a CPU side copy of the texture data. It performed drastically faster in my tests presumably because within the driver it is making a new copy of the texture and so doesn't have to stall if the previous texture is still in use.

There is one other possible solution which I also implemented but no longer use. You can use Android GraphicBuffers. See this link for some basic info: Using Direct Textures on Android This approach lets you write to textures with no stall, however, it's not an officially supported API and I could only get it to work on Mali and only with a lot of effort. It doesn't completely solve the problem on it's own because you still need to do you own sync control, otherwise your App may overwrite the texture data whilst it's being used and you end up with some corruption on screen.

like image 157
Muzza Avatar answered Nov 12 '22 05:11

Muzza