Lots of png files being loaded into textures for use with OpenGLES is causing slow load times - iphone

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?

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.

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.

Related

Disk cache vs Recreating the image

I currently have an app where I do a lot of image manipulation. I basically take an image that is 320x320 (or 640x640 on Retina) and scale it down to 128x128 (or 256x256 on Retina) before rounding off its corners and applying a glossy highlight. Everything is done using Core Graphics drawing.
At any one time there could be around 600 images that need this processing so I do around 40 on app launch using a background thread and cache them into a FIFO queue. When an image not in the cache needs processing, I do so and add it to the end of the cache, discarding the first cached image. If that first image is needed again it goes through the same process.
What I would like to know is if it would make more sense, and is ultimately more efficient, to save the discarded images to disk rather than recreate them from scratch the next time they are needed, as I could instead just read them from disk.
These images are also displayed using a CALayer and therefore there may be a overhead when the layers' contents are set because of the conversion from UIImage to CGImage. If I store them on disk I believe they can be read directly as a CGImage?
Any ideas and input on improving the efficiency of this process will be sincerely welcomed.
My personal choice would be to use a disk cache.
However, you say 'which is more efficient' - what do you mean?
If you mean faster then the disk cache is probably going to win.
If you mean more space efficient then recreating them will win.
If you mean lower memory usage then it entirely depends on your implementation!
You will have to try it and see :)
However, the advantage of the disk solution is that the second time your app starts up, it will already have done the processing so will start faster. That's why I'd use the disk.
From my experience, saving and then reading from the disk is faster. I had some memory warnings by doing it over and over, instead of saving and reading. But, the only to know for sure is to try. I was using around 1000 images, so it makes senses in my case to use the disk.
It's also good to give a try github's libs that downloads and caches UIImage/NSData from Internet.
It may by SDWebImage(https://github.com/rs/SDWebImage) or APSmartStorage (https://github.com/Alterplay/APSmartStorage).
APSmartStorage helps to get data from network and automatically caches data on disk or in memory in a smart configurable way. Should be good enough.

Handling many image files in scrollview on iPhone similar to photos app

So I've seen this question asked before and in fact I asked it last night but I thought I'd give it another go just to see if I could get any other unique views on the problem.
The Problem — I have an app with a large number of uiimageviews (with image downloaded to disk) in a scrollview which of course has two large problems facing it: Memory use, and performance. In my app memory use isn't so much a problem because I am employing techniques such as dequeuing and reusing imageviews and such. But performance is another thing entirely. Right now, as a memory saving procedure, I only store image filepaths in memory because it would be ridiculous to store images in memory. But the problem with this is that reading from the disk takes more time than from memory and slows down scrolling on the scrollview immensely.
So, what kind of techniques do any of you suggest for something like this? I've seen three20 but don't want to use it because I need high customizability in my view and that just won't do. Image files are not large, but just thumbnail size so there is no scaling or excess size. There's got to be an intuitive way to handle this. The built in photos app handles up to thousands of photos perfectly with low memory and slick and smooth scrolling performance.
Fundamentally, the problem is that you're probably doing a bunch of disk I/O on your UI thread, which is basically guaranteed to cause performance problems.
You should consider loading your images on a background thread and updating the image views on the main thread when the images are loaded. Depending on your use case you can get more or less clever about how far you preload in advance, etc, so you can have images ready. (There might be some usable source code or even Apple sample code out there that does something like this, but I don't know of it off the top of my head.)
You may notice that some applications (not sure about the Photos app) have an intermediate stage where they load a very small thumb size image for all images, and scale it up to the render size, which acts as a placeholder until the full size version is loaded-- if the user scrolls past that image before the full size is loaded, the visible effect is nearly the same as if the image was there all along.

Big loading times in iphone app

I'm making an openGL game for iPod/iPhone.
At start I load at once all the textures I need. At first loading times where small, but as I kept developing and adding new textures the loading times have been increasing, to the point of taking many seconds before the game start.
Recently a new problem appeared, when I build the game in the device It takes too long and the game quits. At the app is installed correctly and i can test It, but never while being connected to xcode. Sometimes even the app quits, when too many elements are dran on screen.
Right now I use 6 files , with about 2 Mbs of size in total.
Is there a form to create a loading screenor the such ?
What other meassures can I take so solve this issues ?
If you're decoding PNG files at startup using Core Graphics, I would suggest using PVRTexTool to create PVR data files instead. The contents of PVR files can be uploaded directly to OpenGL; no need to use Core Graphics to decode them.
PVRTexTool can also do neat stuff like generate mipmaps (another thing you might want to avoid at startup time) and encode to compressed formats (reducing your texture size will help too).
Besides encoding your textures as PVR-textures there are a few more solutions.
One is to defer texture loading to a later point. Let your app bring up its user interface and maybe show a progress bar to the user while you're loading your textures. This will stop iPhoneOS from killing your app.
You'll probably also need to look into what kind of textures you are creating. Some formats are much more expensive than others to create from you png:s.
As a last resort you could save your textures as uncompressed raw textures. This will make your app larger but cut down loading time.

iPhone OpenGLES: Textures are consuming too much memory and the program crashes with signal "0"

I am not sure what the problem is. My app is running fine on the simulator but when I try to run it on the iPhone it crashes during debugging or without debugging with signal "0". I am using the Texture2D.m and OpenGLES2DView.m from the examples provided by Apple. I profiled the app on the iPhone with Instruments using the Memory tracer from the Library and when the app died the final memory consumed was about 60Mb real and 90+Mb virtual. Is there some other problem or is the iPhone just killing the application because it has consumed too much memory? If you need any information please state it and I will try to provide it. I am creating thousands of textures at load time which is why the memory consumption is so high. Really cant do anything about reducing the number of pics being loaded. I was running before on just UIImage but it was giving me really low frame rates. I read on this site that I should use OpenGLES for higher frame rates.
Also sub question is there any way not to use UIImage to load the png file and then use the Texture class provided to create the texture for OpenGLES functions to use it for drawing? Is there some function in OpenGLES which will create a texture straight from a png file?
thousands of textures? really? how many of them are on the screen at one time? perhaps you can only load some of them at a time, or if they're small, you should combine them into fewer larger textures.
the general guideline I've heard is that you are limited to 24MB of texture memory.
there's nothing built into OpenGLES that loads from disk, but you can use a file parser like stb_image to do it yourself.
I tried load as ten texture pieces of 2048x2048 pixels.
Texture memory exceed 24MB, but iPhone3GS is able to loaded and rendered it.
I also recommend stb_image or SOIL texture loader.
(stb_image library is used SOIL library.)

Convert .png to PVRTC *on* the iPhone

Is there a standard mechanism or known library that will convert .png images to compressed PVRTC textures on the iPhone itself (not during development using the standard tools on OS X).
I have a number of .png textures in my application but swapping is an issue. I'd like to create PVRTC variants of the .pngs on the device, should the available memory be low on application startup (or perhaps on first load of the application).
I haven't seen any information on the net regarding how to construct PVRTC images manually and to the best of my knowledge there is no support for this built into the iPhone (and it wouldn't be needed to read the PVRTC files).
For most applications, there is little sense to include or construct both versions of the files. Under optimal conditions, the PVRTC versions should be virtually indistinguishable from the PNG versions and are really just "pre-processed" versions of the files optimized for direct streaming into the video memory.
It is generally best to go through all of your images and make decisions regarding how to best package the image to balance memory conservation and quality for all users, not just under specific restricted memory situations.
A few things to consider (apologies if this is redundant knowledge):
PVRTC files can have problems with complex alpha blended images as the pre-processing can cause unsightly artifacts along the blended edges.
Opaque PNG files should have their alpha channel removed in the original image (saving memory and blending overhead).
For images with a limited range of colors, reduce the image from PNG32 to PNG16 or PNG8 to save memory on disk.
If this is for OpenGL based programs, consider using an enhanced version of Texture2D (such as from Cocos2D) which supports alternate pixel formats such as 565 and 4444. This can greatly reduce the overhead in the graphics card with minimal impact on image quality, by carefully choosing a pixel format which corresponds to the balance of colors in the original image.
Additionally for OpenGL based programs, avoid individual images (320x480) for backgrounds as this will result in a 512x512 texture in memory for each one. Break the image into smaller pieces or make the image 512x512 and fill the extra space with other images so that only one texture needs to load.
As with everything, focus on the largest images first to get the biggest bang for the buck.
It's also worth noting that since your application will be the only thing running (other than system applications), the only real memory overhead is going to be a limited amount of "disk" space. Making a second copy of all the image files will actually be working against you instead of helping.
Barney
I'd be careful assuming that this will help you. Once you reference the images once, i.e. load them into a UIImage, the iPhone will start to cache your pngs whether you like them or not. Compressing them will not serve you well to achieve what you're looking for here, in my opinion.
If you want to compress images to PVR on IOS, you may consider the OpenSceneGraph plugin pvr :
http://www.openscenegraph.org/projects/osg/browser/OpenSceneGraph/branches/OpenSceneGraph-3.0/src/osgPlugins/pvr/ReaderWriterPVR.cpp .