I have thousands of png files that I am loading using libpng and then creating OpenGLES textures out of for use in the application. Doing this is causing a huge load time lag on the iPhone. Is there any way to speed up load time?
views:
244answers:
3Lots of png files being loaded into textures for use with OpenGLES is causing slow load times.
You can place several textures in one big texture (1024x1024). This require some re-calculation of the texcoords though. Try also to have the texture parts close to the actual resolution used when drawing, ie if a texture will fill a 1/2 screen height (240px) its good enough to use a texture of 256x256.
Then, a more advanced method (not tested) could be to concatenate all files (+registering their length+pos) and then used mmap(..)
to access this png-db file. Then use NSData
to feed the texture loading function if they are based on UIImage
. The good thing with using mmap(..)
like this is that one don't open and close a lot of files and the access to the data is handled with help of the OS VM manager.
[Note: Yeah, iPhone native PNG loader require some png mangling...might need a none native reader then or concatenate mangled files instead]
Do you know what order you're going to need your thousands of images in? Perhaps you can only load a few hundred of them when your app starts, and then load more on a background thread as you go.
Combining small images into fewer larger textures will also be a good idea, again only if there's some pattern about what images are used together.
What I've typically done is build an object that handles lazy loading of my textures through a manager. At start up I register my known textures and resolve their file system attributes I will need later to save on simple IO at load time, then as they are needed I pull them in.
To speed things up I have a batch load mechanism too, where I say "load this array of images and return them to me." This is simply to remove the overhead of repeated method calls. Indeed, my single load solution is just a simple wrapper around my batch load.
This way at start up I cache my bookkeeping (object creation, file system attribute discovery, etc), but defer heavy work until necessary. As I load textures into my app at run time it triggers faults which fill in the textures from storage to texture memory. If I'm loading a scene with many textures known before hand I load the set of very common textures in a prefetch, but defer relatively uncommonly seen textures to runtime.
In practice this tends to work due to the probabilities involved - forcing the load at start time assures you you'll encounter all textures at once, whereas sparsely loading them in likelihood causes the expected user latency to drop off weighted by load time latency * probability of being loaded within some window of time from start. If you optimize your start time prefetch to not load textures you decrease your expected UI latencies dramatically.
Additionally, you may want to consider using NSURLConnection:connectionWithRequest:delegate: for loading your textures from storage. It is asynchronous so you can ask it to load your largest ones asynchronously and your smaller ones synchronously to take advantage of IO / CPU idle factors during file system fetches / texture decompression (large files load long while small files load fast and can deserialize at the same time). You should test this though since the iPhone may not handle asynchronous file system access well.