How to best load images upfront?

Started by
10 comments, last by futlib 10 years, 11 months ago

I'm working on a 2D game and am starting to see some short lags caused by image decompression (I'm using rather large graphics to support high resolutions). I suppose I'll have to load all my textures upfront and show a loading screen, now I'm wondering how to best go about this. I can think of two approaches:

1. Instantiate all entities for a scene when the scene is being created (Every entity is currently loading its own texture when it is being instantiated, so that should do). The manual effort seems a bit error prone though (easy to forget), and might mess up the code a bit.

2. Have a mapping from image paths to image IDs and use the IDs to load images in the code. That way I can load all the image files when the game starts. But it's tedious to add a mapping for every image I use, and not very flexible as I cannot have loading screens for individual scenes.

I'm not particularly enthusiastic about either approach. How is this commonly being solved? I can find some literature on this that focuses on huge 3D games, but that doesn't seem to apply too well to my small 2D game.

Advertisement

Your entities should not own system resources. They should be state packages that your program operates on. Have either a resource loading system that manages this or else have the scene/state own the resources. The entities should either have an ID referring to what resource they need or else just pointers to the resources they need. It doesn't need to be super complex - just load what you need and pass either a pointer or some other kind of ID into the entity so that your rendering knows which resource to use.

This is the same for a 3D game.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Your entities should not own system resources. They should be state packages that your program operates on.

I'm not convinced that makes things easier in my case. My game is mostly GUI, so I have widgets and screens rather than entities and scenes. And having widgets draw themselves is ubiquitous in UI frameworks.

Have either a resource loading system that manages this or else have the scene/state own the resources. The entities should either have an ID referring to what resource they need or else just pointers to the resources they need. It doesn't need to be super complex - just load what you need and pass either a pointer or some other kind of ID into the entity so that your rendering knows which resource to use.

That sounds like my option 2. Can you think of a better way to implement this then what I came up with, the big mapping? I've pondered this quite a bit, but unless I create all widgets upfront, I cannot possibly know which images are going to be required.

I'm not convinced that makes things easier in my case. My game is mostly GUI, so I have widgets and screens rather than entities and scenes. And having widgets draw themselves is ubiquitous in UI frameworks.

In UI frameworks the widgets draw themselves using resources that are cached or preloaded by the system. Logical objects should not have ownership over shared data. It's bad design in anything that's non-trivial.

That sounds like my option 2. Can you think of a better way to implement this then what I came up with, the big mapping? I've pondered this quite a bit, but unless I create all widgets upfront, I cannot possibly know which images are going to be required.

Then you can implement your resource manager as a cache and map resources by URI or something. It really sounds like you're making this more complicated than it needs to be. What kind of GUI needs so many distinct resources that you're afraid to pre-load all of them? You said that you're using a lot of large images to get high-res results. Are you overstepping the limitations of the system here? Have you benched this yet? How long does it take to pre-load everything?
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

In UI frameworks the widgets draw themselves using resources that are cached or preloaded by the system. Logical objects should not have ownership over shared data. It's bad design in anything that's non-trivial.

In Qt, images are loaded as soon as a QPixmap object is instantiated, causing a lag like the one in my game when lots of large images are being loaded. But anyway, I agree, the widgets shouldn't own the resources. I do have an asset loader already and I can move the image loading into it, and also add caching.

Then you can implement your resource manager as a cache and map resources by URI or something. It really sounds like you're making this more complicated than it needs to be. What kind of GUI needs so many distinct resources that you're afraid to pre-load all of them?

I'm not afraid to preload them all, I think that's going to be necessary. It's only going to be 100-200 MB, so that should be fine even on ancient systems. The OS will page unused resources out anyway. I was thinking that it may be better to have a loading screen for each scene, but I suppose that's not really necessary at this scale.

My problem is that I can't figure out how to preload everything, I never had to think about this before working with less/smaller images. Only the widgets know which images they need, so I see only two options:

1. Instantiate all widgets upfront - they'll load their resources

2. Figure out which images to load without consulting the widgets

Your suggestion sounds like option 2, and it does indeed seem better. Now I'm wondering how to implement that, seeing three options:

2a. Have a mapping between image IDs and image paths - use the image IDs in widgets, preload all the images from the mapping file on startup

2b. Have a file that lists all the resources that should be preloaded

2c. Just load all image files in the directory

2a Seems tedious - I'll have to add every single image file I use there. 2b is similarly tedious and on top of that error prone - it's easy to forget. 2c involves no manual effort, but I have to make assumptions about what to load (e.g. every file name ending with .png) and it may load too much if there are unused resources.

How is that commonly being solved? Considering that many games have loading screens per scene or level, how do they figure out which resources are required upfront?

A simple cache can work such that you simply ask it for the object belonging to a URI (path/file) and it checks to see if the object is loaded. If not it loads, then either way it just returns a pointer to the object. A std::map indexed by strings should be able to manage it. With a system like that you can pre-load any resource simply by calling the cache's load function and ignoring the return value. With this in place you can up-front load the resources necessary to display the program start screen and then background load the GUI resources. Recall that you can have more than one cache active, so you could keep the GUI resources at broad scope and then use a separate instance of the cache class to deal with resources for a scene in the game or something.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Yeah, a cache sounds good, I think I'll go with that. But I still need to figure out which resources to preload, thoughts on that?

2a. Have a mapping between image IDs and image paths - use the image IDs in widgets, preload all the images from the mapping file on startup

2b. Have a file that lists all the resources that should be preloaded

2c. Just load all image files in the directory

2a Seems tedious - I'll have to add every single image file I use there. 2b is similarly tedious and on top of that error prone - it's easy to forget. 2c involves no manual effort, but I have to make assumptions about what to load (e.g. every file name ending with .png) and it may load too much if there are unused resources.

How is that commonly being solved? Considering that many games have loading screens per scene or level, how do they figure out which resources are required upfront?

Just implemented the texture caching. Unfortunately, my memory estimates were quite off as I was doing them based on the size of the compressed images... In reality, having all images in memory causes a resident set of around 280MB, virtual memory usage being around 2.8GB. Considering that we'll probably end up with three times as many images, this seems way too much.

So I suppose I'll have to look into per-scene preloading. The options I considered so far still apply, slightly altered:

2a. Have a mapping between image IDs and image paths, with a separate section for each scene

2b. Have a list of images to preload for each scene

2c. Preload all images in a specific directory at the start of each scene

2c seems pretty unattractive now... Yet I can't imagine that most games handle this by simply hard coding/mapping all image paths (2a/2b).

Can you explain what it is you're doing here? I'm having a hard time imagining a GUI that needs the better part of a gigabyte of texture memory.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Can you explain what it is you're doing here? I'm having a hard time imagining a GUI that needs the better part of a gigabyte of texture memory.

Sure. However, note that the virtual memory size I reported is the vsize returned by top on OS X. It's 2.4 GB for the Python interpreter and even simpler tools like bc. Anyway:

The screen/scene we're talking about is where the player can create his character. He can chose from various variants of body parts (hair styles, eyes and such), all in all there are 63 variants right now. To select a variant, the player touches one of the preview images, so we also have 63 preview images which are scaled down to a width of 500 and cropped to a maximum height of 500. And there are also 63 generated images for the button down effect of the same size. The real body part images are larger, averaging around 1500x1500. Add to that a 3200x1800 background image and some less noteworthy UI graphics and that's about it.

The memory usage I reported earlier was after loading all of the preview images and some of the larger images. If I load absolutely everything, the resident memory is at almost 1 GB and the virtual memory at 3.8 GB. However, much of the larger images are still in the resolution in which the artist provided them, sometimes twice a big as necessary, so I'll be able to cut that down a bit I guess.

I just wrote a script that downscales everything for a resolution of 2000x1125 (factor 0.625), which would suffice on most screens. Virtual memory after loading all the preview images and some of the others is down to 2.8 GB, resident memory to 150 MB (was 2.7 GB and 280 MB respectively before), after loading everything (some of which is still twice as big as necessary) it's at 3.1 GB virtual memory and 500 MB resident memory.

This topic is closed to new replies.

Advertisement