For my spectrum analysis app for the N900 I needed a fast method to render a scrolling 2D graph.
I started by rejecting these options:
- The fastest way to render is with triangle primitives. Wikipedia says PowerVR SGX530 found in Nokia N900 can render as many as 14 million polygons per second. SGX535 on the iPhone can render twice as much (unless the chip there is downclocked of course).
- If you need to scroll through a static image, you can simply map it to a quad and then translate the view matrix to reveal it.
These didn’t suit me, as I wanted it to be a bitmap scroller that gets updated at each frame. So I started with a brute-force approach:
- Update the whole screen at each frame. On the N900, you’ll need to push 1,5 MB of data each frame, and 614 Kb on the iPhone. The scrolling is done in the bitmap itself.
This gave me around 20 fps, which wasn’t enough. So I started to dig deeper:
- The phone supports OpenGL ES 2.0, which means it has FBOs (framebuffer objects).
If you are not familiar with the concept, FBOs allow you to create additional framebuffers (normally you have one — “the screen”), you can switch to them at any point, and all subsequent drawing routines would draw into your custom FBO instead of the screen. The memory for this additional framebuffer is allocated by creating a texture. You can then switch back to the “screen” (FBO with the id of zero) and use your FBO texture like any other texture.
So I figured I could try this (for a horizontal scroller):
- Create two FBOs.
- Create a 1-pixel-wide texture (assuming I’m updating a single column) for the bitmap.
- Draw our texture into FBO #1, then draw FBO #1 on screen.
- Now we also draw FBO #1 into FBO #2, but with 1 pixel shift to the left. This reveals a 1-pixel-wide gap on the right.
- We go to (2) to fill the gap on the right and now switch FBOs. So, it’s a tripple-buffered scroller (if we count the screen as one of the buffers).
If you are still with me, here is a human-readable explanation for this: I wanted only the changed part of the bitmap to be traveling to the GPU at each frame. Textures live in the GPU memory (although I’m not that keen on the mobile architecture to ascertain that it even has dedicated memory), so presumably most of the drawing using this method is done entirely on the GPU.
The result was a not-so-pleasing 20 fps again, or maybe it was 3 fps more, I can’t remember. And, oh, it also had a huge flickering problem due to imperfect texture mapping to screen coordinates (the screen grid is in integer pixels, but texture coordinates are in floats, remember?)
This was a bitch to implement and it didn’t pan out. I started to think how to simplify it and this is when came the revelation of glTexSubImage2D and the brilliant texcoord solution.
- Create a screen-sized texture (in my case, next power of two for 800×480). Put some initial bitmap into it, if needed. Using glTexSubImage2D update a column of pixels (or more, if needed) starting at some variable offset. Then, append the “u” texture coordinate by 1.0/width, and render.
When offset reaches the size of the texture you just continue from the start, as texture will be wrapped by OpenGL automatically, provided you set that option. By the way, glTexSubImage2D doesn’t require the dimensions to be power of two, unlike for the size of the texture itself.
So, the goals are reached: only the modified part of the bitmap is sent to the GPU, and the shifting is done in the most natural way possible, available since OpenGL 1.0. Resulting fps was over 30, and sometimes as high as 45 in my app, I haven’t done a clean test since I was already satisfied with the performance.
The described method will work on any platform that has basic OpenGL support. Check out the source code of Scroller2D class for the details, and feel free to try out my Audelicious app on your N900.






/* the implementation is trickier, and you'll need to release it */



