Cache the result of GetImage() in Vehicle::UpdateViewport() where possible.

Sprite number is not cached if callback is made, or a variable access
outside a whitelist occurs.
Invalidate cached sprite number when direction or cargo changes,
or vehicle is marked dirty.
pull/8/head
Jonathan G Rennison 8 years ago
parent 9ae057b8bf
commit 3ac94e97c8

@ -1293,6 +1293,7 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station)
void Aircraft::MarkDirty()
{
this->colourmap = PAL_NONE;
this->cur_image_valid_dir = INVALID_DIR;
this->UpdateViewport(true, false);
if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this, EIT_ON_MAP);
}

@ -186,6 +186,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
this->z_pos = z;
this->tile = TileVirtXY(x, y);
this->cur_image_valid_dir = INVALID_DIR;
this->UpdateImage();
this->UpdatePositionAndViewport();
@ -199,6 +200,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
u->z_pos = GetSlopePixelZ(safe_x, safe_y);
u->direction = this->direction;
u->cur_image_valid_dir = INVALID_DIR;
u->UpdateImage();
u->UpdatePositionAndViewport();

@ -108,6 +108,7 @@ void GroundVehicle<T, Type>::CargoChanged()
weight += current_weight;
/* Slope steepness is in percent, result in N. */
u->gcache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100;
u->cur_image_valid_dir = INVALID_DIR;
}
/* Store consist weight in cache. */

@ -237,6 +237,8 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver
}
}
bool _sprite_group_resolve_check_veh_enable = false;
bool _sprite_group_resolve_check_veh_result = false;
const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) const
{
@ -252,6 +254,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
/* Try to get the variable. We shall assume it is available, unless told otherwise. */
bool available = true;
if (adjust->variable == 0x7E) {
_sprite_group_resolve_check_veh_result = false;
const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false);
if (subgroup == NULL) {
value = CALLBACK_FAILED;
@ -261,8 +264,49 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
/* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
} else if (adjust->variable == 0x7B) {
_sprite_group_resolve_check_veh_result = false;
value = GetVariable(object, scope, adjust->parameter, last_value, &available);
} else {
if (_sprite_group_resolve_check_veh_enable) {
switch (adjust->variable) {
// whitelist of variables which can be checked without requiring an immediate re-check on the next tick
case 0xC:
case 0x1A:
case 0x1C:
case 0x25:
case 0x40:
case 0x41:
case 0x42:
case 0x47:
case 0x49:
case 0x4B:
case 0x4D:
case 0x60:
case 0x7D:
case 0x7F:
case 0x80 + 0x0:
case 0x80 + 0x1:
case 0x80 + 0x4:
case 0x80 + 0x5:
case 0x80 + 0x39:
case 0x80 + 0x3A:
case 0x80 + 0x3B:
case 0x80 + 0x3C:
case 0x80 + 0x3D:
case 0x80 + 0x44:
case 0x80 + 0x45:
case 0x80 + 0x46:
case 0x80 + 0x47:
case 0x80 + 0x5A:
case 0x80 + 0x72:
case 0x80 + 0x7A:
break;
default:
_sprite_group_resolve_check_veh_result = false;
break;
}
}
value = GetVariable(object, scope, adjust->variable, adjust->parameter, &available);
}

@ -408,6 +408,7 @@ void RoadVehicle::MarkDirty()
{
for (RoadVehicle *v = this; v != NULL; v = v->Next()) {
v->colourmap = PAL_NONE;
v->cur_image_valid_dir = INVALID_DIR;
v->UpdateViewport(true, false);
}
this->CargoChanged();

@ -259,6 +259,7 @@ Trackdir Ship::GetVehicleTrackdir() const
void Ship::MarkDirty()
{
this->colourmap = PAL_NONE;
this->cur_image_valid_dir = INVALID_DIR;
this->UpdateViewport(true, false);
this->UpdateCache();
}

@ -1638,6 +1638,8 @@ static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2)
*/
static void UpdateStatusAfterSwap(Train *v)
{
v->cur_image_valid_dir = INVALID_DIR;
/* Reverse the direction. */
if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
@ -3052,6 +3054,7 @@ void Train::MarkDirty()
Train *v = this;
do {
v->colourmap = PAL_NONE;
v->cur_image_valid_dir = INVALID_DIR;
v->UpdateViewport(true, false);
} while ((v = v->Next()) != NULL);

@ -367,6 +367,7 @@ Vehicle::Vehicle(VehicleType type)
this->cargo_age_counter = 1;
this->last_station_visited = INVALID_STATION;
this->last_loading_station = INVALID_STATION;
this->cur_image_valid_dir = INVALID_DIR;
}
/**

@ -291,6 +291,7 @@ public:
uint16 load_unload_ticks; ///< Ticks to wait before starting next cycle.
GroupID group_id; ///< Index of group Pool array
byte subtype; ///< subtype (Filled with values from #EffectVehicles/#TrainSubTypes/#AircraftSubTypes)
DirectionByte cur_image_valid_dir; ///< NOSAVE: direction for which cur_image does not need to be regenerated on the next tick
NewGRFCache grf_cache; ///< Cache of often used calculated NewGRF values
VehicleCache vcache; ///< Cache of often used vehicle values.
@ -1158,11 +1159,20 @@ struct SpecializedVehicle : public Vehicle {
/* Skip updating sprites on dedicated servers without screen */
if (_network_dedicated) return;
extern bool _sprite_group_resolve_check_veh_enable;
extern bool _sprite_group_resolve_check_veh_result;
/* Explicitly choose method to call to prevent vtable dereference -
* it gives ~3% runtime improvements in games with many vehicles */
if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
SpriteID old_image = this->cur_image;
this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
if (this->cur_image_valid_dir != this->direction) {
_sprite_group_resolve_check_veh_enable = true;
_sprite_group_resolve_check_veh_result = true;
this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
this->cur_image_valid_dir = _sprite_group_resolve_check_veh_result ? this->direction : INVALID_DIR;
_sprite_group_resolve_check_veh_enable = false;
}
if (force_update || this->cur_image != old_image) this->Vehicle::UpdateViewport(true);
}
};

Loading…
Cancel
Save