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 */
|
/* Pseudo sprite processing is finished; free temporary stuff */
|
||||||
_cur_gps.ClearDataForNextFile();
|
_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. */
|
/* Call any functions that should be run after GRFs have been loaded. */
|
||||||
AfterLoadGRFs();
|
AfterLoadGRFs();
|
||||||
|
|
||||||
|
|
|
@ -759,7 +759,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
|
||||||
SpriteID i = 0;
|
SpriteID i = 0;
|
||||||
for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) {
|
for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) {
|
||||||
const SpriteCache *sc = GetSpriteCache(i);
|
const SpriteCache *sc = GetSpriteCache(i);
|
||||||
if (sc->ptr != nullptr) {
|
if (sc->ptr != nullptr && sc->file != nullptr) {
|
||||||
push({ sc->lru, i, sc->length });
|
push({ sc->lru, i, sc->length });
|
||||||
if (candidate_bytes >= to_remove) break;
|
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 */
|
* 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++) {
|
for (; i != static_cast<SpriteID>(_spritecache.size()); i++) {
|
||||||
const SpriteCache *sc = GetSpriteCache(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 });
|
push({ sc->lru, i, sc->length });
|
||||||
while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) {
|
while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) {
|
||||||
pop();
|
pop();
|
||||||
|
@ -825,6 +825,32 @@ void *UniquePtrSpriteAllocator::AllocatePtr(size_t size)
|
||||||
return this->data.get();
|
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.
|
* 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.
|
* 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 */ 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 LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id);
|
||||||
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num);
|
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num);
|
||||||
void DupSprite(SpriteID old_spr, SpriteID new_spr);
|
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 */
|
#endif /* SPRITECACHE_H */
|
||||||
|
|
Loading…
Reference in New Issue