mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Add management of in-memory sprites.
parent
fb7c5e04cf
commit
1a967aad95
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue