NewGRF: Elide unmasked vehicle callbacks where possible
This includes: * CBID_VEHICLE_32DAY_CALLBACK * CBID_VEHICLE_REFIT_COST * CBID_VEHICLE_MODIFY_PROPERTY This is on a per-property basis The main benefit of this is to avoid callbacks not handled by the vehicle's current sprite group from using the full graphics chain as the "default" branch in the callback switch. In the case where the graphics chain is long/expensive, a lot of work had to be done before a callback failure result was eventually returned.
This commit is contained in:
@@ -256,6 +256,162 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
|
||||
return SpriteGroup::Resolve(this->default_group, object, false);
|
||||
}
|
||||
|
||||
void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) const
|
||||
{
|
||||
auto res = op.seen.insert(this);
|
||||
if (!res.second) {
|
||||
/* Already seen this group */
|
||||
return;
|
||||
}
|
||||
|
||||
auto check_1A_range = [&]() -> bool {
|
||||
if (this->adjusts.size() == 1 && this->adjusts[0].variable == 0x1A) {
|
||||
/* Not clear why some GRFs do this, perhaps a way of commenting out a branch */
|
||||
uint32 value = 0;
|
||||
switch (this->size) {
|
||||
case DSG_SIZE_BYTE: value = EvalAdjustT<uint8, int8> (this->adjusts[0], nullptr, 0, UINT_MAX); break;
|
||||
case DSG_SIZE_WORD: value = EvalAdjustT<uint16, int16>(this->adjusts[0], nullptr, 0, UINT_MAX); break;
|
||||
case DSG_SIZE_DWORD: value = EvalAdjustT<uint32, int32>(this->adjusts[0], nullptr, 0, UINT_MAX); break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low <= value && value <= range.high) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (op.mode == ACOM_FIND_CB_RESULT) {
|
||||
if (this->calculated_result) {
|
||||
op.cb_result_found = true;
|
||||
return;
|
||||
} else if (!op.cb_result_found) {
|
||||
if (check_1A_range()) return;
|
||||
if (this->adjusts.size() == 1 && this->adjusts[0].variable == 0xC) {
|
||||
const auto &adjust = this->adjusts[0];
|
||||
if (adjust.shift_num == 0 && (adjust.and_mask & 0xFF) == 0xFF && adjust.type == DSGA_TYPE_NONE) {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low == range.high && range.low == 0xC) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_1A_range()) return;
|
||||
|
||||
auto find_cb_result = [&]() -> bool {
|
||||
if (this->calculated_result) return true;
|
||||
AnalyseCallbackOperation cbr_op;
|
||||
cbr_op.mode = ACOM_FIND_CB_RESULT;
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(cbr_op);
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(cbr_op);
|
||||
return cbr_op.cb_result_found;
|
||||
};
|
||||
|
||||
if (this->adjusts.size() == 1 && !this->calculated_result) {
|
||||
const auto &adjust = this->adjusts[0];
|
||||
if (op.mode == ACOM_CB_VAR && adjust.variable == 0xC) {
|
||||
if (adjust.shift_num == 0 && (adjust.and_mask & 0xFF) == 0xFF && adjust.type == DSGA_TYPE_NONE) {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low == range.high) {
|
||||
switch (range.low) {
|
||||
case CBID_VEHICLE_32DAY_CALLBACK:
|
||||
op.callbacks_used |= SGCU_VEHICLE_32DAY_CALLBACK;
|
||||
break;
|
||||
|
||||
case CBID_VEHICLE_REFIT_COST:
|
||||
op.callbacks_used |= SGCU_VEHICLE_REFIT_COST;
|
||||
break;
|
||||
|
||||
case CBID_VEHICLE_MODIFY_PROPERTY:
|
||||
if (range.group != nullptr) {
|
||||
AnalyseCallbackOperation cb36_op;
|
||||
cb36_op.mode = ACOM_CB36_PROP;
|
||||
range.group->AnalyseCallbacks(cb36_op);
|
||||
if (cb36_op.properties_used == UINT64_MAX) DumpSpriteGroup(range.group, 0);
|
||||
op.properties_used |= cb36_op.properties_used;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (op.mode == ACOM_CB36_PROP && adjust.variable == 0x10) {
|
||||
if (adjust.shift_num == 0 && (adjust.and_mask & 0xFF) == 0xFF && adjust.type == DSGA_TYPE_NONE) {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low == range.high) {
|
||||
if (range.low < 64) {
|
||||
if (find_cb_result()) SetBit(op.properties_used, range.low);
|
||||
}
|
||||
} else {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (op.mode == ACOM_CB36_PROP && adjust.variable == 0xC) {
|
||||
if (adjust.shift_num == 0 && (adjust.and_mask & 0xFF) == 0xFF && adjust.type == DSGA_TYPE_NONE) {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low <= CBID_VEHICLE_MODIFY_PROPERTY && CBID_VEHICLE_MODIFY_PROPERTY <= range.high) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &adjust : this->adjusts) {
|
||||
if (op.mode == ACOM_CB_VAR && adjust.variable == 0xC) {
|
||||
op.callbacks_used |= SGCU_ALL;
|
||||
}
|
||||
if (op.mode == ACOM_CB36_PROP && adjust.variable == 0x10) {
|
||||
if (find_cb_result()) {
|
||||
op.properties_used |= UINT64_MAX;
|
||||
}
|
||||
}
|
||||
if (adjust.variable == 0x7E && adjust.subroutine != nullptr) {
|
||||
adjust.subroutine->AnalyseCallbacks(op);
|
||||
}
|
||||
}
|
||||
if (!this->calculated_result) {
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
}
|
||||
}
|
||||
|
||||
void CallbackResultSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) const
|
||||
{
|
||||
if (op.mode == ACOM_FIND_CB_RESULT) op.cb_result_found = true;
|
||||
}
|
||||
|
||||
const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
|
||||
{
|
||||
|
Reference in New Issue
Block a user