mirror of https://github.com/OpenTTD/OpenTTD
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
parent
f5a6a31e4a
commit
9bc64b553b
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
Loading…
Reference in New Issue