1
0
Fork 0

Codechange: Cache callback spritegroups. (#13111)

Each callback result requires a pool memory allocation, each of which is 24 bytes.

Build a cache of results so that if the same result is used later it refers to the same group.
pull/13129/head
Peter Nelson 2024-11-27 23:25:35 +00:00 committed by GitHub
parent f5a6a31e4a
commit 9bc64b553b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 22 deletions

View File

@ -5131,14 +5131,35 @@ static void SkipAct1(ByteReader &buf)
GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur.skip_sprites); GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur.skip_sprites);
} }
using CachedCallback = std::pair<uint16_t, SpriteGroupID>;
static std::vector<CachedCallback> _cached_callback_groups; ///< Sorted list of cached callback result spritegroups.
static const SpriteGroup *GetCallbackResultGroup(uint16_t value)
{
/* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result.
* New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
if (_cur.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) {
value &= ~0xFF00;
} else {
value &= ~0x8000;
}
/* Find position for value within the cached callback list. */
auto it = std::ranges::lower_bound(_cached_callback_groups, value, std::less{}, &CachedCallback::first);
if (it != std::end(_cached_callback_groups) && it->first == value) return SpriteGroup::Get(it->second);
/* Result value is not present, so make it and add to cache. */
assert(CallbackResultSpriteGroup::CanAllocateItem());
const SpriteGroup *group = new CallbackResultSpriteGroup(value);
it = _cached_callback_groups.emplace(it, value, group->index);
return group;
}
/* Helper function to either create a callback or link to a previously /* Helper function to either create a callback or link to a previously
* defined spritegroup. */ * defined spritegroup. */
static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid) static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid)
{ {
if (HasBit(groupid, 15)) { if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid);
assert(CallbackResultSpriteGroup::CanAllocateItem());
return new CallbackResultSpriteGroup(groupid, _cur.grffile->grf_version >= 8);
}
if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid); GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid);
@ -5158,10 +5179,7 @@ static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint1
*/ */
static const SpriteGroup *CreateGroupFromGroupID(uint8_t feature, uint8_t setid, uint8_t type, uint16_t spriteid) static const SpriteGroup *CreateGroupFromGroupID(uint8_t feature, uint8_t setid, uint8_t type, uint16_t spriteid)
{ {
if (HasBit(spriteid, 15)) { if (HasBit(spriteid, 15)) return GetCallbackResultGroup(spriteid);
assert(CallbackResultSpriteGroup::CanAllocateItem());
return new CallbackResultSpriteGroup(spriteid, _cur.grffile->grf_version >= 8);
}
if (!_cur.IsValidSpriteSet(feature, spriteid)) { if (!_cur.IsValidSpriteSet(feature, spriteid)) {
GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid); GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid);
@ -8862,6 +8880,7 @@ void ResetNewGRFData()
InitializeSoundPool(); InitializeSoundPool();
_spritegroup_pool.CleanPool(); _spritegroup_pool.CleanPool();
_cached_callback_groups.clear();
} }
/** /**
@ -9937,6 +9956,10 @@ extern void InitGRFTownGeneratorNames();
/** Finish loading NewGRFs and execute needed post-processing */ /** Finish loading NewGRFs and execute needed post-processing */
static void AfterLoadGRFs() static void AfterLoadGRFs()
{ {
/* Cached callback groups are no longer needed. */
_cached_callback_groups.clear();
_cached_callback_groups.shrink_to_fit();
for (StringIDMapping &it : _string_to_grf_mapping) { for (StringIDMapping &it : _string_to_grf_mapping) {
it.func(MapGRFStringID(it.grfid, it.source)); it.func(MapGRFStringID(it.grfid, it.source));
} }

View File

@ -230,7 +230,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
if (this->calculated_result) { if (this->calculated_result) {
/* nvar == 0 is a special case -- we turn our value into a callback result */ /* nvar == 0 is a special case -- we turn our value into a callback result */
if (value != CALLBACK_FAILED) value = GB(value, 0, 15); if (value != CALLBACK_FAILED) value = GB(value, 0, 15);
static CallbackResultSpriteGroup nvarzero(0, true); static CallbackResultSpriteGroup nvarzero(0);
nvarzero.result = value; nvarzero.result = value;
return &nvarzero; return &nvarzero;
} }

View File

@ -211,20 +211,8 @@ struct CallbackResultSpriteGroup : SpriteGroup {
/** /**
* Creates a spritegroup representing a callback result * Creates a spritegroup representing a callback result
* @param value The value that was used to represent this callback result * @param value The value that was used to represent this callback result
* @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8.
*/ */
CallbackResultSpriteGroup(uint16_t value, bool grf_version8) : explicit CallbackResultSpriteGroup(uint16_t value) : SpriteGroup(SGT_CALLBACK), result(value) {}
SpriteGroup(SGT_CALLBACK),
result(value)
{
/* Old style callback results (only valid for version < 8) have the highest byte 0xFF so signify it is a callback result.
* New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
if (!grf_version8 && (this->result >> 8) == 0xFF) {
this->result &= ~0xFF00;
} else {
this->result &= ~0x8000;
}
}
uint16_t result; uint16_t result;
uint16_t GetCallbackResult() const override { return this->result; } uint16_t GetCallbackResult() const override { return this->result; }