Jump to content

  • Log In with Google      Sign In   
  • Create Account

How to best load images upfront?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 23 April 2013 - 03:16 AM

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.


Edited by futlib, 23 April 2013 - 03:18 AM.


Sponsor:

#2 Khatharr   Crossbones+   -  Reputation: 3038

Like
0Likes
Like

Posted 23 April 2013 - 03:24 AM

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.

#3 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 23 April 2013 - 06:28 AM

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.



#4 Khatharr   Crossbones+   -  Reputation: 3038

Like
0Likes
Like

Posted 24 April 2013 - 03:04 AM

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?

Edited by Khatharr, 24 April 2013 - 03:05 AM.

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.

#5 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 24 April 2013 - 07:11 AM

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?



#6 Khatharr   Crossbones+   -  Reputation: 3038

Like
0Likes
Like

Posted 24 April 2013 - 05:01 PM

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.

#7 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 24 April 2013 - 09:44 PM

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?



#8 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 25 April 2013 - 07:24 AM

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).


Edited by futlib, 25 April 2013 - 07:47 AM.


#9 Khatharr   Crossbones+   -  Reputation: 3038

Like
0Likes
Like

Posted 26 April 2013 - 05:37 AM

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.

#10 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 26 April 2013 - 09:14 PM

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.


Edited by futlib, 26 April 2013 - 09:48 PM.


#11 Khatharr   Crossbones+   -  Reputation: 3038

Like
0Likes
Like

Posted 27 April 2013 - 02:28 PM

I would not consider thumbnails or displayed images to be GUI elements. That's just normal content. You can use one cache for your gui elements, one for the thumbnails and then load the larger images as needed, either through another cache (for fast switching) or else just raw, depending on how you're setting this up. You can allow your cache class to be aware of its memory usage and to be able to limit itself according to customizable parameters then do internal housecleaning using whatever method makes the most sense for what you're doing.

 

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.

 

Wouldn't it be worth using a different method to indicate the button-down state, such as just changing the blend on the button, or overlaying a semi-transparent colored quad?

 

Also, you may want to explore downsampling for some of the less critical images. You could potentially save a lot of space using indexed color or even just 16-bit color depth. It really depends on what the images look like. I know memory and disk storage are abundant these days but I'd be uncomfortable using 0.95 MB just for a thumbnail, especially if there's a lot of them.


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.

#12 futlib   Members   -  Reputation: 197

Like
0Likes
Like

Posted 27 April 2013 - 11:40 PM

You can use one cache for your gui elements, one for the thumbnails and then load the larger images as needed, either through another cache (for fast switching) or else just raw, depending on how you're setting this up. You can allow your cache class to be aware of its memory usage and to be able to limit itself according to customizable parameters then do internal housecleaning using whatever method makes the most sense for what you're doing.

 

That sounds good, that way I'll be able to keep memory usage under control.

 

Still, I see a notable lag when loading just one of the larger images on older systems, so I really think I'll have to do some preloading with a proper loading screen. Still not sure which approach to go with for that.

 

I'm somewhat back at square one in that I'm again considering to have the scene preload everything it needs itself. Widgets don't own their resources anymore, so it's not as difficult to implement as it was when I started this thread. I can just clear the cache after each scene (maybe having a global area with things that are never cleared).

 

Wouldn't it be worth using a different method to indicate the button-down state, such as just changing the blend on the button, or overlaying a semi-transparent colored quad?

Also, you may want to explore downsampling for some of the less critical images. You could potentially save a lot of space using indexed color or even just 16-bit color depth. It really depends on what the images look like. I know memory and disk storage are abundant these days but I'd be uncomfortable using 0.95 MB just for a thumbnail, especially if there's a lot of them.

 

Well, the game runs on Android, so disk storage is not that abundant :) Good ideas, I'll look into these if downscaling isn't sufficient.


Edited by futlib, 27 April 2013 - 11:46 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS