Change: Treat recolour sprites as regular sprites in the SpriteCache. (#13107)

Recolour sprites are loaded when seen, instead of being loaded when needed. This could result in the sprite cache being filled up with recolour sprites, and also mean that replacing recolour sprites didn't release the previously allocated memory.

Instead, allow recolour sprites to be loaded as needed and freed when unneeded, like regular sprites.
This commit is contained in:
Peter Nelson 2024-11-23 12:14:46 +00:00 committed by GitHub
parent 00ae20fa02
commit b890dab2b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 6 deletions

View File

@ -418,10 +418,12 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, uint8_t sprite
/** /**
* Load a recolour sprite into memory. * Load a recolour sprite into memory.
* @param file GRF we're reading from. * @param file GRF we're reading from.
* @param file_pos Position within file.
* @param num Size of the sprite in the GRF. * @param num Size of the sprite in the GRF.
* @param allocator Sprite allocator to use.
* @return Sprite data. * @return Sprite data.
*/ */
static void *ReadRecolourSprite(SpriteFile &file, uint num, SpriteAllocator &allocator) static void *ReadRecolourSprite(SpriteFile &file, size_t file_pos, uint num, SpriteAllocator &allocator)
{ {
/* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small /* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small
* number of recolour sprites that are 17 bytes that only exist in DOS * number of recolour sprites that are 17 bytes that only exist in DOS
@ -430,6 +432,7 @@ static void *ReadRecolourSprite(SpriteFile &file, uint num, SpriteAllocator &all
static const uint RECOLOUR_SPRITE_SIZE = 257; static const uint RECOLOUR_SPRITE_SIZE = 257;
uint8_t *dest = allocator.Allocate<uint8_t>(std::max(RECOLOUR_SPRITE_SIZE, num)); uint8_t *dest = allocator.Allocate<uint8_t>(std::max(RECOLOUR_SPRITE_SIZE, num));
file.SeekTo(file_pos, SEEK_SET);
if (file.NeedsPaletteRemap()) { if (file.NeedsPaletteRemap()) {
uint8_t *dest_tmp = new uint8_t[std::max(RECOLOUR_SPRITE_SIZE, num)]; uint8_t *dest_tmp = new uint8_t[std::max(RECOLOUR_SPRITE_SIZE, num)];
@ -634,9 +637,9 @@ bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
file.ReadByte(); file.ReadByte();
return false; return false;
} }
file_pos = file.GetPos();
type = SpriteType::Recolour; type = SpriteType::Recolour;
CacheSpriteAllocator allocator; file.SkipBytes(num);
data = ReadRecolourSprite(file, num, allocator);
} else if (file.GetContainerVersion() >= 2 && grf_type == 0xFD) { } else if (file.GetContainerVersion() >= 2 && grf_type == 0xFD) {
if (num != 4) { if (num != 4) {
/* Invalid sprite section include, ignore. */ /* Invalid sprite section include, ignore. */
@ -675,6 +678,7 @@ bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
SpriteCache *sc = AllocateSpriteCache(load_index); SpriteCache *sc = AllocateSpriteCache(load_index);
sc->file = &file; sc->file = &file;
sc->file_pos = file_pos; sc->file_pos = file_pos;
sc->length = num;
sc->ptr = data; sc->ptr = data;
sc->lru = 0; sc->lru = 0;
sc->id = file_sprite_id; sc->id = file_sprite_id;
@ -835,7 +839,7 @@ static void DeleteEntryFromSpriteCache()
cur_lru = 0xffff; cur_lru = 0xffff;
for (SpriteID i = 0; i != _spritecache_items; i++) { for (SpriteID i = 0; i != _spritecache_items; i++) {
SpriteCache *sc = GetSpriteCache(i); SpriteCache *sc = GetSpriteCache(i);
if (sc->type != SpriteType::Recolour && sc->ptr != nullptr && sc->lru < cur_lru) { if (sc->ptr != nullptr && sc->lru < cur_lru) {
cur_lru = sc->lru; cur_lru = sc->lru;
best = i; best = i;
} }
@ -977,7 +981,13 @@ void *GetRawSprite(SpriteID sprite, SpriteType type, SpriteAllocator *allocator,
sc->lru = ++_sprite_lru_counter; sc->lru = ++_sprite_lru_counter;
/* Load the sprite, if it is not loaded, yet */ /* Load the sprite, if it is not loaded, yet */
if (sc->ptr == nullptr) sc->ptr = ReadSprite(sc, sprite, type, cache_allocator, nullptr); if (sc->ptr == nullptr) {
if (sc->type == SpriteType::Recolour) {
sc->ptr = ReadRecolourSprite(*sc->file, sc->file_pos, sc->length, cache_allocator);
} else {
sc->ptr = ReadSprite(sc, sprite, type, cache_allocator, nullptr);
}
}
return sc->ptr; return sc->ptr;
} else { } else {
@ -1056,7 +1066,7 @@ void GfxClearSpriteCache()
/* Clear sprite ptr for all cached items */ /* Clear sprite ptr for all cached items */
for (uint i = 0; i != _spritecache_items; i++) { for (uint i = 0; i != _spritecache_items; i++) {
SpriteCache *sc = GetSpriteCache(i); SpriteCache *sc = GetSpriteCache(i);
if (sc->type != SpriteType::Recolour && sc->ptr != nullptr) DeleteEntryFromSpriteCache(i); if (sc->ptr != nullptr) DeleteEntryFromSpriteCache(i);
} }
VideoDriver::GetInstance()->ClearSystemSprites(); VideoDriver::GetInstance()->ClearSystemSprites();

View File

@ -24,6 +24,7 @@ struct SpriteCache {
void *ptr; void *ptr;
size_t file_pos; size_t file_pos;
SpriteFile *file; ///< The file the sprite in this entry can be found in. SpriteFile *file; ///< The file the sprite in this entry can be found in.
uint32_t length; ///< Length of sprite data.
uint32_t id; uint32_t id;
int16_t lru; int16_t lru;
SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.