Loading PNG images quickly


I’m working on a project in which I need to load a bunch of PNG files from disk to OpenGL and display them as textures. But there’s a problem with speed / memory usage. So my question is, what is the most optimum way to handle loading PNG images?

I use Qt4 to load the image data, and then pass it to glTexImage2D() and I use internal format GL_COMPRESSED_RGBA_S3TC_DXT3_EXT (or DXT1, 3, 5). But this seems to be quite slow as the image is compressed on the fly. Can I use glCompressedTexImage2D() to load the compressed PNG images directly from disk? If yes, how? I haven’t managed to get it working. If I load without compression, the images take way too much memory. Also I think I need mipmaps. So what is the best way to do this?

As far as I know, PNG’s don’t support DXTC compressed data.
The only thing you can do is, as a pre-process step, load the png’s, compress them using the GL functions or something like Squish (or maybe even CUDA squish), then dump them to your own in-house binary image format, or dump them as dds files (which are the only common image format to support DXTC compression, as far as I know). When you load them at run-time you can directly pass the data to glCompressedTexImage2D.

What knackered said.

PNGs are compressed (similar to “zip compressed”) images. Graphics cards don’t use that form of compression, instead they use block compressed textures with fixed compression ratio (because random access to any part of texture is needed).

So if you’re loading PNGs at runtime, and creating DXT textures, there are several places where time is spent:

  1. read PNG from disk
  2. decompress PNG into uncompressed RGB(A) data
  3. pass uncompressed data to the driver
  4. driver compresses into DXT3
  5. driver uploads to the graphics card

Now, if you create RGBA textures, then of course the textures will use much more VRAM and bandwidth while rendering, but you’ll save step 4. Which is still quite slow and suboptimal for VRAM/bandwidth.

If you can, doing steps 1-4 offline, saving DXT data into DDS files or simple custom format is the way to go. In that case, the steps to read the texture would be:

  1. read DXT bytes from disk
  2. pass those bytes to the driver
  3. driver uploads to the graphics card
    So here there’s no costly DXT compression and PNG decompression.

Of course, if the PNG files are not known beforehand, then your only options are either using DXT, or using uncompressed data. You could try not letting the driver encode to DXT, but do that yourself, using some fast DXT compression (e.g. nvidia’s texture tools have lower quality, but fast, compressor).

You could also try to multithread your application, if it runs on multicore CPUs. Read bytes from disk and decompress PNG on one thread, DXT compress on another thread, pass data to OpenGL in yet another thread. This won’t be a speed increase if you’re just loading one image, but if you’re loading a bunch of them, it might.

Thanks for the replies.

I could load the PNG files offline, and convert them into DDS. How would I dump my images into DDS files on disk? Without using any external application. Is there a library that does it or simply a method in OpenGL to do that? Loading seems not to be problem, because Qt supports loading DDS files, but not saving them (as far as I know).