ImageManager: Load vs Reserve vs Request

WickedWolfy

Touch Fluffy Tail!
Veteran
Joined
Nov 27, 2017
Messages
113
Reaction score
49
First Language
En
Primarily Uses
RMMV
Greetings, colleagues,

Could someone take a moment and explain to me the difference between the three different operations of ImageManager please?
I have walked through the functions and have a basic understanding of the functionality, but use-cases escape me.

Just to make it more specific, I am looking at "loadBitmap", "reserveBitmap" and "requestBitmap" as a main example.
I've noticed there is a sense of caching... but is that it? Just pre-caching the images?

Thank you in advance.
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
I know this is an old topic, but Archeia said I should just reply here. xD I was actually looking for the same information, but since I couldn't find it, I went into the code and figured it out on my own. I figured that it would be useful to share this information with everyone.

So the first thing to know is what processes the image goes through before being displayed on the screen.

  • read - The image is loaded from a permanent storage medium. This means basically that the file has been read as such into RAM. e.g. If the file is 30kB, the RAM consumption at this point is 30kB.
  • decode - The image is decoded into a raw bitmap. This means that e.g. a PNG files has been decompressed and all actual pixels are now in the RAM. If that image is e.g. 1000x1000 pixels with alpha, the size in RAM is now 1000x1000x4 = 4 million Bytes.
  • upload to GPU - This means that the GPU now has access to the texture data of the bitmap and can render it. In the previous case from Load it would mean that the texture now also takes 4 million bytes of VRAM.

Keep in mind that Bitmap size information (width and height) will only become available after decode has been done.

So what do the separate ImageManager functions do?
  • Request - Starts the read process asynchronously, but stops after that. So this is useful e.g. if you want to avoid doing HDD operations while the player is actually playing the game.
  • Load - Starts the read process asynchronously and will run decode automatically after the file has been read from the permanent storage.
  • Reserve - Does the same as the Load, but also marks the bitmap as "keep in memory". I will explain image memory below.

You probably noticed that the upload to GPU step is missing here and you are correct. The upload to GPU step is done internally the moment the first render call is used. Incidentally if you alter a bitmap (e.g. with drawText() or fillRect() calls), the bitmap is marked as dirty and will be reuploaded again the next time it is drawn. This is also why it's not recommended to constantly keep changing bitmaps. Uploading texture data to the GPU is an expensive operation.

The way the ImageCache system works is that it has a fixed size of pixels (not bytes!) that it's allowed to keep in memory. The variable ImageCache.limit is set to 10 million pixels by default. This translates to e.g. 10 images of size 1000x1000. If the limit has been surpassed, the ImageCache module will delete the last recently used images until it's under that limit again, but it keeps all reserved images regardless of that. Most of the images from the img/system directory are actually reserved like that globally, ie. they are never removed from the cache.

If you intend to use Reserve with anything other than system images, there are 2 additional things that you have to keep in mind.

  • All images reserved are local for the current scene and they will be "released" from reservation after the scene is finished. That means that images can be purged by ImageCache after the scene is finished (unless obviously they are reserved again in another scene).
  • Do NOT reserve any images before the create method of the scene has been called. Reservations work via IDs that can be released later and the SceneManager creates that ID for every scene just before calling the scene's create method. My suggestion is to actually call it within the scene's create method. You can even call it before the superclass call to give the ImageManager more time to preload your images.
 
Last edited:

WickedWolfy

Touch Fluffy Tail!
Veteran
Joined
Nov 27, 2017
Messages
113
Reaction score
49
First Language
En
Primarily Uses
RMMV
Thanks for the late post. I did kind of figure it out some time after posting.

TLDR:
It has to do with cache and how your computer needs to clear its memory to be able to serve your game better. RPG Maker MV has a way to load and store sprites and templates to run the game faster.

If you plan to use "Request" option, use it wisely.

I've been messing around with optimizations of sprites for my game projects. Trying to max the storage and seeing what would happen. =3

@bblizzard Have you figured out if its FIFO system for kicking out older loaded items, or something else?
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
@WickedWolfy Yes, it's quite simple, but it's actually not a FIFO. Each time a texture is rendered, it's "touched". That means that its time variable is set to the current timestamp. When the cache is filled up, textures are sorted by those timestamps and the oldest ones are removed until ImageCache is under the given limit again. So the least recently used textures are removed. I thought I explained it well enough in my post above. (^_^')

Yeah, I obviously had to figure it out myself as well. xD It's a relatively simple, but effective memory management method based on memory budget.
 

Restart

Veteran
Veteran
Joined
Mar 15, 2019
Messages
523
Reaction score
413
First Language
English
Primarily Uses
RMMV
[*]All images reserved are local for the current scene and they will be "released" from reservation after the scene is finished. That means that images can be purged by ImageCache after the scene is finished (unless obviously they are reserved again in another scene).
Does that explain why maps with a ton of events sometimes have a lag spike when closing the menu - because it has to load all the images from harddisk again?
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
39,949
Reaction score
13,585
First Language
English
Primarily Uses
RMMV
The map scene is only "finished" when you return to the title screen or exit the game. While the menu is loaded, the map scene still exists.
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
Actually that's true. All scenes are pushed onto a stack so only a game over or a switch to the title screen would actually finish the map scene.
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
This is exactly what I've been looking for.
However, the ImageManager.reserveSystem(windowSkin2); function I inserted in the Scene create method makes no difference to the loaded menu text.

Sometimes the Window Skin is loaded, other times not. It's totally random. I was hoping reserving the window skin would help, but apparently not. Is there anything else I'm missing? Do I have to set a Reservation ID in the reserveSystem method?
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
Are you using a custom plugin of sorts? "windowSkin2" isn't present anywhere in the default code.

If you're using system images, you should probably add that call in Scene_Boot to load it at the very beginning of the start-up, not in a scene's create method. Other system images are reserved like that as well.
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
Are you using a custom plugin of sorts? "windowSkin2" isn't present anywhere in the default code.

If you're using system images, you should probably add that call in Scene_Boot to load it at the very beginning of the start-up, not in a scene's create method. Other system images are reserved like that as well.
Sorry, I should have provided more background information.
windowSkin2 is a const referring to the string "Window2", a secondary window skin that I want to assign to one specific window within my costum menu, while the rest of the windows have the default system skin. When loading the menu scene, the costum window is created and within the window create method is the line for ImageManager.reserveSystem(windowSkin2);
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
527
Reaction score
230
First Language
English
Primarily Uses
RMMV
Try calling reserveSystem in the scene create method instead of the window create method.
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
Then I definitely think that you should put it in Scene_Boot where all the other ImageManager.reserveSystem() calls are.
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
Then I definitely think that you should put it in Scene_Boot where all the other ImageManager.reserveSystem() calls are.
I totally missed checking where the default window skin is actually loaded. Totally makes sense. I added my second window skin and it works beautifully! I've been having this maddening bug for over 3 months now and you finally lifted the curse! Thank so very much! Have a great day :)
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
No problem, you too. :D

I remember when I first realized how this worked. I used Bitmap.blt() and couldn't figure out why it wouldn't draw the loaded bitmap onto the target bitmap initially. Later I figured out because it wasn't loaded yet and I had to use ImageManager.reserveSystem() to make sure it was actually loaded when I was blitting it. xD
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
No problem, you too. :D

I remember when I first realized how this worked. I used Bitmap.blt() and couldn't figure out why it wouldn't draw the loaded bitmap onto the target bitmap initially. Later I figured out because it wasn't loaded yet and I had to use ImageManager.reserveSystem() to make sure it was actually loaded when I was blitting it. xD
The thing that drove me crazy was it's total randomness. 9 times out of 10 it would load properly and then a few days later, while testing something totally different, the bug came back. I felt like it was haunting me, whenever I least expected it to hit me. To be honest, I still don't feel safe, like this is gonna pop in my face again some day lol
 

bblizzard

Veteran
Veteran
Joined
Nov 6, 2017
Messages
382
Reaction score
377
First Language
Croatian
Primarily Uses
RMMV
Don't worry, it's safe this time. :) Scene_Boot won't continue/exit until the ImageManager says it's ready. And the ImageManager won't say it's ready until the graphics are loaded. You can check ImageManageris.isReady, ImageCache.prototype.isReady and Bitmap.prototype.isReady for reference.

BTW, a good advice for the future: If a bug happens randomly, there's a good change it's a race condition caused by threading and async calls.
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
Don't worry, it's safe this time. :) Scene_Boot won't continue/exit until the ImageManager says it's ready. And the ImageManager won't say it's ready until the graphics are loaded. You can check ImageManageris.isReady, ImageCache.prototype.isReady and Bitmap.prototype.isReady for reference.

BTW, a good advice for the future: If a bug happens randomly, there's a good change it's a race condition caused by threading and async calls.
Thanks for the tipp. I'll at least know what to look for next time something like this happens.
Image processing is a whole nother beast in MV I realized.
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
527
Reaction score
230
First Language
English
Primarily Uses
RMMV
I'm confused. I'm calling ImageManager.reserveCharacter() in a scene's create function, but the images still don't show up when the scene is opened... but only the first time. If I close and reopen the scene, they show up.

Isn't the scene supposed to wait for those reserved images to be ready before starting the scene? When I try to draw the image for the first time, the bitmap's _loadingState is "requesting", which I assume is part of the reason it's not working.

I can probably work around it by calling refresh() at some point after the scene is loaded, but is that the only option, or am I actually doing something wrong?
 

Lanzy

Veteran
Veteran
Joined
Feb 29, 2020
Messages
106
Reaction score
46
First Language
English
Primarily Uses
RMMV
I'm confused. I'm calling ImageManager.reserveCharacter() in a scene's create function, but the images still don't show up when the scene is opened... but only the first time. If I close and reopen the scene, they show up.

Isn't the scene supposed to wait for those reserved images to be ready before starting the scene? When I try to draw the image for the first time, the bitmap's _loadingState is "requesting", which I assume is part of the reason it's not working.

I can probably work around it by calling refresh() at some point after the scene is loaded, but is that the only option, or am I actually doing something wrong?

I had the same problem you are having right now.
The solution:

You have to reserve the image in Scene_Boot. Simply add your ImageManager.reserveCharacter() in there. That should work.

Just like bblizzard showed me a few posts ago.
 

Attachments

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
527
Reaction score
230
First Language
English
Primarily Uses
RMMV
I am 90% sure that that is wrong. Other scenes, built-in scenes, call reserveFaceImages in their create, and that works. There's also Scene_File which calls reserveCharacter in its create. So there must be a way that works without putting it in Scene_Boot.

For a custom window skin, yeah, Scene_Boot makes sense; but for characters, I don't believe that's the right answer.
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

What theme for the next windowskin? You'll decide. Tell what you wanna see and I'll try for.
I just saw in a manga an interesting mechanic - setting up a stationary teleport beacon that one can go to no matter where one is in a dungeon. I think it'll work with a similar setup to how I did my airship transition.

Ooh what if you could set up multiple beacons and choose from a list of the beacons you set up?

Hmm...
Actor2_1 added!

Is the running performance of MZ output to Android platform smoother than MV output?
FINALLY GOT ALL 120 STARS IN SUPER MARIO 64!!!

Forum statistics

Threads
103,251
Messages
998,360
Members
134,749
Latest member
Meppo
Top