pvr effective for large number of small textures?

I have an iPad app that uses a ton(500+) of
small(128x128, 256x256 or less) textures with alpha. At any given time
there are probably 30~90 of these textures loaded with around 30

The app has slightly slow load times when I use PNG files so i am trying to improve them by using pvr textures.

I want to keep as much quality as possible so there is very little difference between the PNG file and PVR file.

So when I tried converting all of my textures with:

-fOGLPVRTC4 -pvrtciterations8 -pvrtcmedium -yflip0

the file sizes generally increased and the loading times did as well.
I know if I use really large textures(1024x1024) then it improves greatly but with small ones it seems not to.

So my question is, is there a way to improve the load times(file size isint much of an issue) even with small textures?

PS. I know that probably creating texture atlases would work but
unfortunately I am too far into development to make that kind of change.

Any kind of info or tips is appreciated.

For the small files, the loading times may be increasing due to file access masking any benefits in PVRTC’s faster texture upload time and lack of decompression requirement before use by GL.

As the textures get larger the balance may be shifting the other way.

(Note: I too would suggest atlases really are the best way to go here, both for loading and runtime performance)

Why are the PVRTC files larger?

In general, uncompressed image data is either 24bpp (RGB) or 32bpp (RGBA) flatrate. PVRTC is 4bpp (or 2bpp) flatrate so there is a compression of 6 or 8 (12 or 16) times compared to this.

A requirement for graphics hardware to use textures natively is that the format of the texture must be random accessible for the hardware. PVRTC is this kind of format, PNG is not and this is why PNG can achieve greater compression ratios. PVRTC is a runtime, deployment format; PNG is a storage format.

PVRTC compression is carried out on 4x4 blocks of pixels at a time and at a flat bit rate so it is easy to calculate where in memory to retrieve the data required to derive a particular texel’s value from and there is only one access to memory required. There is dedicated circuitry in the graphics core which will decode this 4x4 block and give the texel value to your shader/texture combiner etc.

PNG compression does not work at a flat bitrate and is more complicated to retrieve specific values from; memory needs to be accessed from multiple locations in order to retrieve a single colour value and far more memory and processing would be required every single time a texture read occurs. So it’s not suitable for use as a native texture format and this is why your textures must be decompressed before the graphics hardware will use them - so the textures that the graphics core actually uses are 32bpp or 24bpp. This increases bandwidth use when compared to PVRTC, which requires no decompression for use.

So, for offline storage (the size of your application on disk), PNG is smaller than PVRTC which is smaller than completely uncompressed. For runtime memory footprint and performance, PVRTC is smaller and faster than PNG which, because it must be decompressed, is just as large and slow as uncompressed textures. So you gain some advantage with PNG at initialisation for disk access, but then you lose time for decompression.

PVRTC is also in the correct data ordering for POWERVR hardware and doesn’t need to be re-ordered when uploaded to GL so, combined with their smaller data size, PVRTC textures should also upload faster. GL implementations usually only actually perform the upload step at the first use of the texture so if you want to avoid potential waits half-way through a scene it’s worth rendering some unseen triangles with the texture when you don’t mind the processing happening.

If you want to reduce the storage footprint of PVRTC you could try zip-style compression on the texture files and expand these at runtime when you load from disk. This might work out faster.

You could also pack multiple .pvr files into a container file, load this in a single file access and then upload the actual textures separately, as well.

If you can’t get the load performance you need with just PVRTC files then consider using a mixture of PNG and PVRTC - after loading GL treats them identically, after all.

Have you considered keeping the smaller files in memory permanently and only swapping the larger textures in and out?