1
0
Fork 0

Codechange: Add management of in-memory sprites.

pull/11634/head
Peter Nelson 2025-07-25 08:56:50 +01:00
parent fb7c5e04cf
commit 1a967aad95
No known key found for this signature in database
GPG Key ID: 8EF8F0A467DF75ED
3 changed files with 77 additions and 2 deletions

View File

@ -1855,6 +1855,9 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
/* Pseudo sprite processing is finished; free temporary stuff */
_cur_gps.ClearDataForNextFile();
/* Make note of last sprite ID loaded for dynamic sprite management */
ClearDynamicSprites();
/* Call any functions that should be run after GRFs have been loaded. */
AfterLoadGRFs();

View File

@ -759,7 +759,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
SpriteID i = 0;
for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) {
const SpriteCache *sc = GetSpriteCache(i);
if (sc->ptr != nullptr) {
if (sc->ptr != nullptr && sc->file != nullptr) {
push({ sc->lru, i, sc->length });
if (candidate_bytes >= to_remove) break;
}
@ -768,7 +768,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
* only sprites with LRU values <= the maximum (i.e. the top of the heap) need to be considered */
for (; i != static_cast<SpriteID>(_spritecache.size()); i++) {
const SpriteCache *sc = GetSpriteCache(i);
if (sc->ptr != nullptr && sc->lru <= candidates.front().lru) {
if (sc->ptr != nullptr && sc->file != nullptr && sc->lru <= candidates.front().lru) {
push({ sc->lru, i, sc->length });
while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) {
pop();
@ -825,6 +825,32 @@ void *UniquePtrSpriteAllocator::AllocatePtr(size_t size)
return this->data.get();
}
/**
* Allocate and inject memory for a memory-based sprite.
*/
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len)
{
if (SpriteExists(load_index)) GetSpriteCache(load_index)->ClearSpriteData();
SpriteCache *sc = AllocateSpriteCache(load_index);
sc->file_pos = SIZE_MAX;
sc->file = nullptr;
sc->id = 0;
sc->lru = 0;
sc->type = type;
sc->warned = false;
sc->control_flags = {};
UniquePtrSpriteAllocator cache_allocator;
cache_allocator.Allocate<std::byte>(len);
sc->ptr = std::move(cache_allocator.data);
sc->length = static_cast<uint32_t>(cache_allocator.size);
_spritecache_bytes_used += sc->length;
return {sc->ptr.get(), sc->length};
}
/**
* Handles the case when a sprite of different type is requested than is present in the SpriteCache.
* For SpriteType::Font sprites, it is normal. In other cases, default sprite is loaded instead.
@ -958,3 +984,44 @@ void GfxClearFontSpriteCache()
}
/* static */ SpriteCollMap<ReusableBuffer<SpriteLoader::CommonPixel>> SpriteLoader::Sprite::buffer;
static SpriteID _sprites_end; ///< First usable free sprite ID.
static std::vector<uint32_t> _dynamic_sprites; ///< List of used/free custom sprite slots.
/**
* Clear custom sprites mapping and set first usable free sprite ID.
*/
void ClearDynamicSprites()
{
_dynamic_sprites.clear();
_sprites_end = _spritecache.size();
}
/**
* Allocate a custom sprite ID.
*/
SpriteID AllocateDynamicSprite()
{
/* Find first unused slot, or make one. */
auto it = std::ranges::find(_dynamic_sprites, 0);
if (it == std::end(_dynamic_sprites)) it = _dynamic_sprites.emplace(it, 0);
(*it)++;
return _sprites_end + std::distance(std::begin(_dynamic_sprites), it);
}
/**
* Mark a custom sprite ID as deallocated.
* The sprite slot is merely marked as reusable.
*/
void DeallocateDynamicSprite(SpriteID sprite)
{
if (sprite >= _sprites_end && sprite < _sprites_end + _dynamic_sprites.size()) {
assert(_dynamic_sprites[sprite - _sprites_end] > 0);
--_dynamic_sprites[sprite - _sprites_end];
if (_dynamic_sprites[sprite - _sprites_end] == 0) {
GetSpriteCache(sprite)->ClearSpriteData();
}
}
}

View File

@ -59,5 +59,10 @@ size_t GetGRFSpriteOffset(uint32_t id);
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id);
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num);
void DupSprite(SpriteID old_spr, SpriteID new_spr);
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len);
void ClearDynamicSprites();
SpriteID AllocateDynamicSprite();
void DeallocateDynamicSprite(SpriteID spite);
#endif /* SPRITECACHE_H */