Image Loading Thread (that doesn't slow down display loop)?

Hi,

I’m sure there is a simple answer to this question-- I hope someone out there has a few seconds to point me in the right direction or even supply me with some code or psuedocode.

What’s the best way to bind images to a texture in real time?

My application needs to read jpegs from a remote database every 60 seconds or so. Every time it binds an image to a texture (using glTexImage2D) the display loop pauses for about 5 seconds. The slowness is definitely from the binding and not from the image loading. I’ve tried to move the code into its own thread, but I get strange behavior where the polygon appears but no texture is actually bound to it, or the entire polygon turns white.

As long as the binding occurs in the background then I actually don’t care about the speed of the binding-- I just don’t want it to pause and mess up my display loop!!!

Here’s my actual bindTexture method :

	
public void bindTexture(PhotoData photodata)
	{
		gl.glBindTexture(gl.GL_TEXTURE_2D, photodata.textureID);
		gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_MAG_FILTER,gl.GL_LINEAR);
		gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR);
		
		ByteBuffer bb = ByteBuffer.wrap(photodata.data);
		gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, 3, photodata.width, photodata.height, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, bb);
	}

And this method is being called after I’ve loaded in an image (into my simple PhotoData class) remotely like so :


Image img = new ImageIcon(myURL).getImage();

Then I use PixelGrabber to get the bytes for the image before calling my bindTexture as above. Currently this is all triggered by pressing the space bar, so there is no timer thread at all right now, except I’m using the Animator class to display. I’m using Java 1.6 beta 2/JSR-231 beta 5 on a PC.

Thanks!

-spiraljetty

There is no way around this. At the end of the day you’ve got 1 video card with 1 lot of RAM in it and if you try to upload an image to it, everything else is probably going to have to wait in turn.

The reason it doesn’t work in another thread is because OpenGL only allows one Thread to have control of the context.

How big is this image anyway? It should still upload in a matter of microseconds.

Cas :slight_smile:

Hi,

Thanks for the response. The images are not large at all. Maybe 500K at the very most. Usually more like 100K. It’s fine if the binding takes a couple of milliseconds, but currently it’s taking a few seconds, which is obviouly a problem! I’ll post a super simple version of the problem later today and maybe you (or somebody) can run it and see where I’ve gone wrong. Basically I think the PixelGrabber and ByteBuffer.wrap and texture binding code should either be close to instantaneous or somehow be put in a low priority thread so it doesn’t interrupt the display thread.

Thanks,

spiraljetty

I had some generic image loading code in my codebase that also used PixelGrabber since that seemed the only way to get pixels out of an Image. I noticed some stuttering on texture loads and a quick profiling showed that PixelGrabber was the culprit. I now have two code paths, a generic one for Image and an optimized one for BufferedImage. The BufferedImage version uses BufferedImage#getRGB and is a lot faster than the PixelGrabber version.

  1. Load, and convert the pixels to a ByteBuffer in thread A

  2. Upload the ByteBuffer to the GPU in thread B

Step 2 takes roughly 5-50ms for a 512x512 RGBA texture

Also, using GL_BGRA often yields better performance, especially on NVIDIA hardware.

http://developer.nvidia.com/object/fast_texture_transfers.html tells you what sort of transfer speeds to expect once you got your image data in a ByteBuffer.

Thanks for all your help. It turns out that it is indeed flaky to try to share the GL context with different threads. So the obvious solution (suggested by Riven) is to do all the image loading from a new thread, but actually do the binding from within the display loop once the image is fully loaded. Futzing around with the different image formats (GL_BGRA) seems to speed up the binding slightly as well (thanks mabraham).

Thanks again!

-spiraljetty