Skip to content

Commit

Permalink
Spritecache: Move SpriteCache, SpriteDataBuffer to internal header
Browse files Browse the repository at this point in the history
  • Loading branch information
JGRennison committed Dec 13, 2023
1 parent 898b790 commit c49c373
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 177 deletions.
181 changes: 4 additions & 177 deletions src/spritecache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "core/mem_func.hpp"
#include "video/video_driver.hpp"
#include "scope_info.h"
#include "spritecache.h"
#include "spritecache_internal.h"

#include "table/sprites.h"
#include "table/strings.h"
Expand All @@ -32,185 +34,15 @@

#include "safeguards.h"

static const uint RECOLOUR_SPRITE_SIZE = 257;

/* Default of 4MB spritecache */
uint _sprite_cache_size = 4;

static size_t _spritecache_bytes_used = 0;
size_t _spritecache_bytes_used = 0;
static uint32 _sprite_lru_counter;
static uint32 _spritecache_prune_events = 0;
static size_t _spritecache_prune_entries = 0;
static size_t _spritecache_prune_total = 0;

struct SpriteCache;

class SpriteDataBuffer {
friend SpriteCache;

std::unique_ptr<void, FreeDeleter> ptr;
uint32 size = 0;

public:
void *GetPtr() { return this->ptr.get(); }
uint32 GetSize() { return this->size; }

void Allocate(uint32 size)
{
this->ptr.reset(MallocT<byte>(size));
this->size = size;
}

void Clear()
{
this->ptr.reset();
this->size = 0;
}
};

struct SpriteCache {
SpriteFile *file; ///< The file the sprite in this entry can be found in.
size_t file_pos;

private:
std::unique_ptr<void, NoOpDeleter> ptr;

public:
uint32 id;
uint count;

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.
uint8 total_missing_zoom_levels = 0; ///< Zoom levels missing entirely
uint16 flags; ///< Control flags, see SpriteCacheCtrlFlags

void *GetPtr() { return this->ptr.get(); }
const void *GetPtr() const { return this->ptr.get(); }

SpriteType GetType() const { return this->type; }
void SetType(SpriteType type) { this->type = type; }
bool GetWarned() const { return HasBit(this->flags, SCCF_WARNED); }
void SetWarned(bool warned) { SB(this->flags, SCCF_WARNED, 1, warned ? 1 : 0); }
bool GetHasPalette() const { return GB(this->flags, SCC_PAL_ZOOM_START, 6) != 0; }
bool GetHasNonPalette() const { return GB(this->flags, SCC_32BPP_ZOOM_START, 6) != 0; }

private:
void Deallocate()
{
if (!this->ptr) return;

if (this->GetType() == SpriteType::Recolour) {
_spritecache_bytes_used -= RECOLOUR_SPRITE_SIZE;
free(this->ptr.release());
return;
}

Sprite *p = (Sprite *)this->ptr.release();
while (p != nullptr) {
Sprite *next = p->next;
_spritecache_bytes_used -= p->size;
free(p);
p = next;
}
}

Sprite *GetSpritePtr() { return (Sprite *)this->ptr.get(); }

public:
void Clear()
{
this->Deallocate();
this->total_missing_zoom_levels = 0;
}

void RemoveByMissingZoomLevels(uint8 lvls)
{
Sprite *base = this->GetSpritePtr();
if (base == nullptr) {
return;
}
if (base->missing_zoom_levels == lvls) {
/* erase top level entry */
this->ptr.reset(base->next);
_spritecache_bytes_used -= base->size;
free(base);
base = this->GetSpritePtr();
}
if (base == nullptr) {
this->total_missing_zoom_levels = 0;
return;
}
this->total_missing_zoom_levels = base->missing_zoom_levels;
Sprite *sp = base;
while (sp != nullptr) {
this->total_missing_zoom_levels &= sp->missing_zoom_levels;

if (sp->next != nullptr && sp->next->missing_zoom_levels == lvls) {
/* found entry to erase */
_spritecache_bytes_used -= sp->next->size;
Sprite *new_next = sp->next->next;
free(sp->next);
sp->next = new_next;
}

sp = sp->next;
}
}

void Assign(SpriteDataBuffer &&other)
{
this->Clear();
if (!other.ptr) return;

this->ptr.reset(other.ptr.release());
if (this->GetType() == SpriteType::Recolour) {
_spritecache_bytes_used += RECOLOUR_SPRITE_SIZE;
} else {
this->GetSpritePtr()->size = other.size;
_spritecache_bytes_used += other.size;
if (this->GetType() == SpriteType::Normal) {
this->total_missing_zoom_levels = this->GetSpritePtr()->missing_zoom_levels;
}
}
other.size = 0;
}

void Append(SpriteDataBuffer &&other)
{
assert(this->GetType() == SpriteType::Normal);

if (!this->ptr || this->total_missing_zoom_levels == UINT8_MAX) {
/* Top level has no data or no zoom levels at all, it's safe to replace it because it cannot be cached for a render job */
this->Assign(std::move(other));
return;
}

Sprite *sp = (Sprite *)other.ptr.release();
if (sp == nullptr) return;

sp->size = other.size;

Sprite *p = this->GetSpritePtr();
while (p->next != nullptr) {
p = p->next;
}
p->next = sp;
this->total_missing_zoom_levels &= sp->missing_zoom_levels;
_spritecache_bytes_used += other.size;
other.size = 0;
}

~SpriteCache()
{
this->Clear();
}

SpriteCache() = default;
SpriteCache(const SpriteCache &other) = delete;
SpriteCache(SpriteCache &&other) = default;
SpriteCache& operator=(const SpriteCache &other) = delete;
SpriteCache& operator=(SpriteCache &&other) = default;
};

static std::vector<SpriteCache> _spritecache;
static SpriteDataBuffer _last_sprite_allocation;
static std::vector<std::unique_ptr<SpriteFile>> _sprite_files;
Expand All @@ -220,12 +52,7 @@ static inline SpriteCache *GetSpriteCache(uint index)
return &_spritecache[index];
}

static inline bool IsMapgenSpriteID(SpriteID sprite)
{
return IsInsideMM(sprite, SPR_MAPGEN_BEGIN, SPR_MAPGEN_END);
}

static SpriteCache *AllocateSpriteCache(uint index)
SpriteCache *AllocateSpriteCache(uint index)
{
if (index >= _spritecache.size()) {
_spritecache.resize(index + 1);
Expand Down
Loading

0 comments on commit c49c373

Please sign in to comment.