Off screen rendering and texture uploading

Monkey Targets Forums/Android/Off screen rendering and texture uploading

Karja(Posted 2012) [#1]
I decided to try to optimize the Android version of my li'l game, and the first thing I wanted to tackle was the slow text rendering. The easiest way seemed to be to create a bitmap via off screen rendering. That works fine and dandy - but there's an issue with uploading the texture to video memory.

The steps I perform are:

1) Create a "backbuffer", draw each individual character, and then create a gxtkSurface from it.
2) When calling the Draw method of the backbuffer, I use the normal DrawSurface in mojo.

However, the texture doesn't get uploaded to video mem before I actually do a DrawSurface call. Which means that I get a flicker - first it renders nothing for a frame or two, and then - after the texture is uploaded - it shows the texture as expected.

"Well OK," I thought. "I'll just call it directly when I create the gxtkSurface." No dice. It needs to be called in OnRender, not OnUpdate.

Alright, I thought; then I do a double-rendering for a frame or two. I draw both the backbuffer and the original text, and after that I only use the backbuffer. I'll still gain some performance in the long run. But that causes a major delay on my HTC Desire. Uploading a texture to video mem is EXTREMELY slow on my Desire... So the app freezes for a second.

In summary: does anyone know a good way to handle texture uploading? Can it be performed in a separate thread? Can it be sped up? Should I use another format than ARBG_8888? This slowness is also causing major problems for my loading class - I need to first load the textures (which is fast), and then I need to present a static screen while pre-caching everything, which takes AGES.

FYI, my experimental backbuffer code:

Import "native/backbuffer.${TARGET}.${LANG}"

Import mojo

Extern 

Class Backbuffer="fontBackbuffer"
	Method Create(w:Int, h:Int)
	Method SetColor(r:Int, g:Int, b:Int)
	Method DrawImageRect(image:Surface, startx:Int, starty:Int, x:Int, y:Int, w:Int, h:Int)
	Method Finalize()
	Method Draw(x:Int, y:Int)
End Class

Public

Function DrawBackbufferImageRect(b:Backbuffer, image:Image, startx:Int, starty:Int, x:Int, y:Int, w:Int, h:Int)
	b.DrawImageRect(image.surface, startx, starty, x, y, w, h)
End


class fontBackbuffer{
	private Bitmap backbuffer = null;
	private Canvas canvas = null;
	private gxtkSurface surface = null;
	private Paint paint = null;

	public void Create(int w, int h) {
		backbuffer = Bitmap.createBitmap( w+16, h+16, Bitmap.Config.ARGB_8888 );
		canvas = new Canvas( backbuffer );
	}

	public void SetColor(int r, int g, int b) {
		int col = Color.argb( 255, r, g, b );
		paint = new Paint( col );
		ColorFilter filter = new PorterDuffColorFilter( col, PorterDuff.Mode.MULTIPLY );
		paint.setColorFilter( filter );
	}

	public void DrawImageRect(gxtkSurface image, int startx, int starty, int x, int y, int w, int h) {
		canvas.drawBitmap( image.bitmap, new Rect(x, y, x+w, y+h), new Rect(startx+8, starty+8, startx+w+8, starty+h+8), paint );
	}
	
	public void Finalize() {
		surface = new gxtkSurface( backbuffer );
	}

	public void Draw(int x, int y) {
		bb_graphics.bb_graphics_ValidateMatrix();
		bb_graphics.bb_graphics_context.f_device.DrawSurface( surface, x - 8, y - 8 );
    }
}


Note: Extra padding at the sides due to a rendering issue with AngelCode. Also, some mojo modifications are necessary, to make Surface public instead of private.


muddy_shoes(Posted 2012) [#2]
How big is this backbuffer you're using? I'm doing something similar for text and not seeing any huge pause on my android phone. My UI text elements create their own buffers just big enough for the text.


Karja(Posted 2012) [#3]
They're small - 150x50, 300x80 and sizes like that. But, granted, I often create a few text objects at once (e.g. when creating a dialog).

But in other words it seems like I'm not doing anything too weird? Thanks for reassuring me regarding that! I'll just have to think of ways to make it less noticeable for the player.

But I still feel a bit frustrated. It seems like every other game on my phone runs smoothly, but my Monkey stuff have all these stutters whenever the textures are uploading.


muddy_shoes(Posted 2012) [#4]
All I can say is that I do something similar and it's fine for me. I've got a different phone (ZTE Blade) and my other texture usage is fairly light though. I think my heaviest usage of this method is sixteen or so text elements and I don't see any terrible glitches.


muddy_shoes(Posted 2012) [#5]
Oh, by the way. I remembered the discovery of much faster texture binding solution in this thread: http://www.monkeycoder.co.nz/Community/posts.php?topic=2589

You might want to read it and give it a try.


Samah(Posted 2012) [#6]
For offscreen rendering, you may want to take a look at framebuffer objects:
http://en.wikipedia.org/wiki/Framebuffer_Object


muddy_shoes(Posted 2012) [#7]
FBOs are fine as long as you can be sure that the OGL implementation supports them (and even if it claims to that it does so properly). I use them on iOS, but I've got no desire to try it with Android as the platform currently stands.


Karja(Posted 2012) [#8]
Thanks a lot for the hints! Going to read up on the other thread, and consider FBOs as well. I'm a bit reluctant on having anything that might be a cause of errors on Android though; I've heard a lot of how hard it is to ensure compatibility across phone models.

I ought to work on the actual gameplay instead, but I got kind of sidetracked on this optimization. :)