Request/Queue GFX routine
This routine has two primary functions which depends on wheter the sprite has been its needed graphics on VRAM and accesible at the current frame (more on this later).
The first function is the one that puts the necessary tiles which are not present nor accessible
in a queue to upload them to VRAM at the start of the next frame/NMI interrupt. This function also covers other aspects of the whole system:
- Decompress ExGFX file (which can be up to 3KiB)
- Mark tiles in SP3/SP4 as used so any other sprite which requests their graphics to be uploaded to VRAM don't overwrite these used slots
- Save the tiles used to two buffers: a temporal one which will be overwritten the next time the routine is called and a persistent one that holds the same data as the temporal one as long the sprite remains in memory/in screen and can be requested at any time. The persistent buffer is actually a big buffer that holds the information for up to 32 different ExGFX's tile number data, basically an array of arrays.
The second function is far less complex but still very important, it requests the tile data from the persistent buffer which is copied into the temporal buffer for easy access in the sprite code. The routine won't provide any data if the tiles haven't been uploaded to VRAM.
There are moments in the video where you can see a lot of duplicated graphics which ends up looking really bad. This was due to them being marked as "not accessible" or "unused" since no sprite or any other code tried to use these graphics in the previous frames, thus making necessary to put the tiles into the VRAM queue again.
The graphics will be marked as "unused" once a certain amount of frames have passed since the last time their tile data was requested. The default duration is 16 frames, I'm still experimenting with this so it may change later (presumably to a little higher value).
VRAM queue system
A queue system to upload graphics to VRAM was pretty much needed to upload the needed graphics in small chunks every frame to avoid any kind of flickering/overflow.
I designed the system to be a ring/circular buffer with 64 possible entries while each entry holds 4 bytes worth of data. The data stored is a VRAM destination (2 bytes) and the RAM buffer location (2 bytes, bank byte hardcoded to $41). It being a ring buffer helps to avoid making complex calculations when it comes to update the index used in the routine.
Every frame it will try to upload a fixed amount of 16x16 tiles (7 at this moment) in the quickest way I could come up with. I haven't measured the routine in regards of its cycle usage yet, so the amount of tiles uploaded each frame may be reduced depending on how demanding this is.
The system may be used to upload different things to other VRAM regions, but I haven't done anything with that :
New sprite detector
Kinda misleading title, but it isn't a new version of some sprite detector, it detects sprites which where spawned in the current frame.
It sounds like a kinda unnecessary thing, but it was needed to avoid an extra frame of delay for sprie graphics to appear in some cases where sprites were spawned in the same frame and their slot wasn't executed, thus not putting their graphics into the VRAM queue (if needed). It also helps to upload graphics for extended and cluster sprites. And finally, it helps to avoid hijacking every single spawn routine in the whole game.
This routine it's just a bunch of loops and it's quite slow... but if it helps me to not hijack a lot of places (more than I actually have lol), then it's a good trade.
The garbage collector is the routine in charge of marking tiles as unused every frame. It doesn't do much, but it's still quite important part of the whole system.
It was already explained, but again with a little extra details: to get sprite graphics to be marked as unused, the ExGFX file should not be called for a fixed amount of frames. Once a sprite GFX is marked as unused, everything about them will be marked as unused, this includes their data in the persistent buffer, making the tiles in VRAM not accesible, even if they're present.
You can simply avoid getting graphics marked as unused if you request their data from the persistent buffer using the included routine (or just reset their timer), this isn't limited to sprites, you can also do this via UberASM or custom blocks!