0
\$\begingroup\$

I'm currently optimising a C++ OpenGL game, and I've noticed something slightly odd about texture loading.

I've got a number of PNG files I load as textures and use as spritesheets; these are generally 512px or 1024px, with one 2048px. I use SOIL (www.lonesock.net/soil.html) to load the PNGs then bind them to a custom OpenGL texture class.

I've put some primitive code in to measure how long it takes to load these PNG files as textures measured in ticks. Generally speaking the load times are:

512px PNG: 100 - 150 ticks 1024px PNG: 400 - 500 ticks 2048px PNG: 1800 - 2000 ticks

Now I recognise that not all image files are created equally, but these don't quite seem to add up with what I understand in terms of texture files. There's not much to be gained by using fewer larger textures compared to more smaller textures, and often there's no gain for that 2048px PNG compared to four 1024px.

My question is, are these (relative) load times normal? Is there something I'm missing when it comes to loading textures with SOIL?

Note that my question isn't 'how can I generically speed up image loading times' (I may at a later date convert these to more OpenGL friendly file formats like DDS), but more is there a pattern I should / shouldn't be using to optimise this?

Thanks

Nathan

\$\endgroup\$
  • 3
    \$\begingroup\$ I don't see the problem here, an image that is 4 times as large is taking 4 times as long to load. That's what I'd expect to happen. \$\endgroup\$ – Elva Aug 2 '16 at 15:41
  • 1
    \$\begingroup\$ Why do you even care for those ultra-short loading times - what is the original motivation behind this question? \$\endgroup\$ – wondra Aug 2 '16 at 15:42
  • \$\begingroup\$ @KevinvanderVelden - that's interesting, I was under the (possibly erroneous) impression that fewer larger textures loaded faster than multiple smaller ones, and that there was some efficiency to be gained by combining sprites into one large 'atlas' \$\endgroup\$ – nathanburns Aug 3 '16 at 17:14
  • \$\begingroup\$ @Wondra - The main motivation is that currently on game start the player is stuck looking at a black screen. I'm aware of the possibilities of separate threads for loading resources but given this is a relatively simple 2D game with simple sprites, I'd like to avoid this complexity if possible. In isolation the loading time is short, but with enough files can add up to ~10 seconds - which for me is too long \$\endgroup\$ – nathanburns Aug 3 '16 at 17:16
4
\$\begingroup\$

A 2048x2048 image is 4 times as large as a 1024x1024 image which in turn is 4 times as large as a 512x512 image. You're getting a loading time that increases linearly with image size, which is the behaviour you should expect.

PNG, however, is not the best format for storing game graphics which must be sent to an API like OpenGL. While PNG files are small and can be read off disk quickly enough, they are slow to decompress in memory, and because no graphics hardware has native support for PNGs, they must be decompressed before the graphics hardware can use them.

Despite this there are possibly areas where you can optimise further. For example, if you're using GL_RGB/GL_UNSIGNED_BYTE or GL_RGBA/GL_UNSIGNED_BYTE for your format/type parameters to glTexImage, you should consider switching to GL_BGRA instead (and one some hardware use GL_UNSIGNED_INT_8_8_8_8_REV instead of GL_UNSIGNED_BYTE): using these you'll be telling OpenGL that your data is already in the format and layout that the GPU prefers, and so your driver will probably load the data directly rather than doing it's own intermediate format conversion.

As an alternative to PNG, DDS files with DXT compression (patent expires 2nd October 2017, but is not normally a problem since GPU vendors have licensed it anyway) require between one-quarter and one-eighth the storage of an uncompressed image and are natively supported by most GPUs. Loading can be as fast as memory-mapping a file, reading some header data, then sending some pointers directly through glTexImage. No format conversions, no intermediate buffers, no heavy computation: what's on disk is the same as what's used by the GPU. DXT compression is lossy, however.

Finally, you appear to be misunderstanding the purpose of "using fewer larger textures compared to more smaller textures" - it's absolutely nothing to do with load times, but instead is to allow for better draw call batching and fewer state changes at runtime.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the tips - I'll try these out and see how they work. Perhaps you're right, I was under the impression that loading times would be improved as well but there is a fairly linear progression which makes sense. In terms of file format, it's something I'll look at at a later date; PNG files (and other common file formats) are much easier to edit and deal with, largely because of their commonality \$\endgroup\$ – nathanburns Aug 4 '16 at 15:26
  • \$\begingroup\$ Note that DXT compression uses S3TC, which is patented. \$\endgroup\$ – ElementW Aug 7 '16 at 13:49
  • \$\begingroup\$ @ElementW - this is not normally a problem. \$\endgroup\$ – Maximus Minimus Aug 7 '16 at 14:48
  • \$\begingroup\$ @ElementW - updated for S3TC patent expiry date. \$\endgroup\$ – Maximus Minimus May 10 '17 at 18:33
0
\$\begingroup\$

SOIL is a little bit buggy and some things don't load at all or will take an inordinate amount of time to load. Especially large png files. SOIL is a little old and just doesn't seem to like some of the newer formats and encodings all that much.

If I get a photo from a third party I always resave it as a lossless jpeg or similar file with no thumbnails or comments in it. Your results don't seem too terrible but doing this will probably save you some headache down the road.

Probably tiff files are the easiest for it to deal with, but I don't like them too much because windows doesn't know how to deal with them ie it won't give me a preview through windows explorer.

\$\endgroup\$
  • \$\begingroup\$ I've read about tiff files and also read similar to what you've stated i.e. they're a bit fiddly to use compared to something more like PNG - I'll bear these in mind though, possibly for converting PNG to tiff for a final release. As a side note, is there another image loading library you would recommend? I tried a few and had the most success with SOIL, so stuck with it \$\endgroup\$ – nathanburns Aug 3 '16 at 17:17
  • \$\begingroup\$ That's what I am using for now. It works 95% of the time. I also used freeimage.sourceforge.net and it seemed pretty good. I just am using SOIL now because it was being used in one of the tutorials I started building my game engine with. The other one seems more current, though it may have issues as well for all I know. \$\endgroup\$ – Yudrist Aug 3 '16 at 20:52
0
\$\begingroup\$

Bit of an old question but I've actually discovered what the problem here was. My instinct that basic loading of 2D textures was taking a long time was correct for the following reason:

When using the SOIL library I used the flags "SOIL_FLAG_MIPMAPS" and "SOIL_FLAG_COMPRESS_TO_DXT". Removing the "SOIL_FLAG_MIPMAPS" (no real need in a fixed camera 2D game) reduced loading time by a third, and removing "SOIL_FLAG_COMPRESS_TO_DXT" reduced this by a factor of about 50 (i.e. 1000 game ticks down to 20 game ticks), whether using PNG or DDS source file format. I'm yet to fully determine the benefits of the compress to dxt flag, there doesn't appear to be any change in memory, but I'll continue to experiment.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.