Micro-optimize icon smoothing subsystem, cutting down more than 50% of its init time (about .8s drop on local, more on prod) (#69741)

With atoms now being 50% of the init time instead of ~80%, I've decided to poke around other subsystems.

Unfortunately they're not straight forward at all and extremely boring. bitmask_smooth() in particular is just a big proc that is called ~60k times, so I made some adjustments to its macro to reduce ops.

I removed code that looped over two entire Z-levels to find things to smooth, added by e2dd404, at a time before the initialize system. This doesn't have huge gains since it just defers to the queue anyway, but it still shaved off 0.1-0.2s on local.

I removed update_appearance(~UPDATE_SMOOTHING) from something since the person who added it doesn't remember why and it doesn't appear to do anything. Lemon thinks it's something to do with emissives, but I tested with neon carpet and it seemed to work fine.
This commit is contained in:
Mothblocks
2022-12-06 08:55:12 +13:00
committed by GitHub
parent 292019cf08
commit 6dff45d977
2 changed files with 87 additions and 82 deletions
+86 -78
View File
@@ -54,45 +54,6 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define DEFAULT_UNDERLAY_ICON_STATE "plating"
#define SET_ADJ_IN_DIR(source, junction, direction, direction_flag) \
do { \
var/turf/neighbor = get_step(source, direction); \
if(!neighbor) { \
if(source.smoothing_flags & SMOOTH_BORDER) { \
junction |= direction_flag; \
}; \
}; \
else { \
if(!isnull(neighbor.smoothing_groups)) { \
for(var/target in source.canSmoothWith) { \
if(!(source.canSmoothWith[target] & neighbor.smoothing_groups[target])) { \
continue; \
}; \
junction |= direction_flag; \
break; \
}; \
}; \
if(!(junction & direction_flag) && source.smoothing_flags & SMOOTH_OBJ) { \
for(var/obj/thing in neighbor) { \
if(!thing.anchored || isnull(thing.smoothing_groups)) { \
continue; \
}; \
for(var/target in source.canSmoothWith) { \
if(!(source.canSmoothWith[target] & thing.smoothing_groups[target])) { \
continue; \
}; \
junction |= direction_flag; \
break; \
}; \
if(junction & direction_flag) { \
break; \
}; \
}; \
}; \
}; \
} while(FALSE)
///Scans all adjacent turfs to find targets to smooth with.
/atom/proc/calculate_adjacencies()
. = NONE
@@ -165,8 +126,6 @@ DEFINE_BITFIELD(smoothing_junction, list(
else
CRASH("smooth_icon called for [src] with smoothing_flags == [smoothing_flags]")
SEND_SIGNAL(src, COMSIG_ATOM_SMOOTHED_ICON)
update_appearance(~UPDATE_SMOOTHING)
/atom/proc/corners_diagonal_smooth(adjacencies)
switch(adjacencies)
@@ -319,7 +278,6 @@ DEFINE_BITFIELD(smoothing_junction, list(
return NO_ADJ_FOUND
/**
* Basic smoothing proc. The atom checks for adjacent directions to smooth with and changes the icon_state based on that.
*
@@ -329,8 +287,48 @@ DEFINE_BITFIELD(smoothing_junction, list(
/atom/proc/bitmask_smooth()
var/new_junction = NONE
// cache for sanic speed
var/canSmoothWith = src.canSmoothWith
var/smooth_border = (smoothing_flags & SMOOTH_BORDER)
var/smooth_obj = (smoothing_flags & SMOOTH_OBJ)
#define SET_ADJ_IN_DIR(direction, direction_flag) \
set_adj_in_dir: { \
do { \
var/turf/neighbor = get_step(src, direction); \
if(neighbor) { \
var/neighbor_smoothing_groups = neighbor.smoothing_groups; \
if(neighbor_smoothing_groups) { \
for(var/target in canSmoothWith) { \
if(canSmoothWith[target] & neighbor_smoothing_groups[target]) { \
new_junction |= direction_flag; \
break set_adj_in_dir; \
}; \
}; \
}; \
if(smooth_obj) { \
for(var/atom/movable/thing as anything in neighbor) { \
var/thing_smoothing_groups = thing.smoothing_groups; \
if(!thing.anchored || isnull(thing_smoothing_groups)) { \
continue; \
}; \
for(var/target in canSmoothWith) { \
if(canSmoothWith[target] & thing_smoothing_groups[target]) { \
new_junction |= direction_flag; \
break set_adj_in_dir; \
}; \
}; \
}; \
}; \
} else if (smooth_border) { \
new_junction |= direction_flag; \
}; \
} while(FALSE) \
}
for(var/direction in GLOB.cardinals) //Cardinal case first.
SET_ADJ_IN_DIR(src, new_junction, direction, direction)
SET_ADJ_IN_DIR(direction, direction)
if(!(new_junction & (NORTH|SOUTH)) || !(new_junction & (EAST|WEST)))
set_smoothed_icon_state(new_junction)
@@ -338,20 +336,22 @@ DEFINE_BITFIELD(smoothing_junction, list(
if(new_junction & NORTH_JUNCTION)
if(new_junction & WEST_JUNCTION)
SET_ADJ_IN_DIR(src, new_junction, NORTHWEST, NORTHWEST_JUNCTION)
SET_ADJ_IN_DIR(NORTHWEST, NORTHWEST_JUNCTION)
if(new_junction & EAST_JUNCTION)
SET_ADJ_IN_DIR(src, new_junction, NORTHEAST, NORTHEAST_JUNCTION)
SET_ADJ_IN_DIR(NORTHEAST, NORTHEAST_JUNCTION)
if(new_junction & SOUTH_JUNCTION)
if(new_junction & WEST_JUNCTION)
SET_ADJ_IN_DIR(src, new_junction, SOUTHWEST, SOUTHWEST_JUNCTION)
SET_ADJ_IN_DIR(SOUTHWEST, SOUTHWEST_JUNCTION)
if(new_junction & EAST_JUNCTION)
SET_ADJ_IN_DIR(src, new_junction, SOUTHEAST, SOUTHEAST_JUNCTION)
SET_ADJ_IN_DIR(SOUTHEAST, SOUTHEAST_JUNCTION)
set_smoothed_icon_state(new_junction)
#undef SET_ADJ_IN_DIR
///Changes the icon state based on the new junction bitmask. Returns the old junction value.
/atom/proc/set_smoothed_icon_state(new_junction)
@@ -361,36 +361,46 @@ DEFINE_BITFIELD(smoothing_junction, list(
/turf/closed/set_smoothed_icon_state(new_junction)
. = ..()
if(smoothing_flags & SMOOTH_DIAGONAL_CORNERS)
switch(new_junction)
if(
NORTH_JUNCTION|WEST_JUNCTION,
NORTH_JUNCTION|EAST_JUNCTION,
SOUTH_JUNCTION|WEST_JUNCTION,
SOUTH_JUNCTION|EAST_JUNCTION,
NORTH_JUNCTION|WEST_JUNCTION|NORTHWEST_JUNCTION,
NORTH_JUNCTION|EAST_JUNCTION|NORTHEAST_JUNCTION,
SOUTH_JUNCTION|WEST_JUNCTION|SOUTHWEST_JUNCTION,
SOUTH_JUNCTION|EAST_JUNCTION|SOUTHEAST_JUNCTION
)
icon_state = "[base_icon_state]-[smoothing_junction]-d"
if(!fixed_underlay && new_junction != .) // Mutable underlays?
var/junction_dir = reverse_ndir(smoothing_junction)
var/turned_adjacency = REVERSE_DIR(junction_dir)
var/turf/neighbor_turf = get_step(src, turned_adjacency & (NORTH|SOUTH))
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, offset_spokesman = src, plane = FLOOR_PLANE)
// Avoid calling ..() here to avoid setting icon_state twice, which is expensive given how hot this proc is
. = smoothing_junction
smoothing_junction = new_junction
if (!(smoothing_flags & SMOOTH_DIAGONAL_CORNERS))
icon_state = "[base_icon_state]-[smoothing_junction]"
return .
switch(new_junction)
if(
NORTH_JUNCTION|WEST_JUNCTION,
NORTH_JUNCTION|EAST_JUNCTION,
SOUTH_JUNCTION|WEST_JUNCTION,
SOUTH_JUNCTION|EAST_JUNCTION,
NORTH_JUNCTION|WEST_JUNCTION|NORTHWEST_JUNCTION,
NORTH_JUNCTION|EAST_JUNCTION|NORTHEAST_JUNCTION,
SOUTH_JUNCTION|WEST_JUNCTION|SOUTHWEST_JUNCTION,
SOUTH_JUNCTION|EAST_JUNCTION|SOUTHEAST_JUNCTION,
)
icon_state = "[base_icon_state]-[smoothing_junction]-d"
if(new_junction == . || fixed_underlay) // Mutable underlays?
return .
var/junction_dir = reverse_ndir(smoothing_junction)
var/turned_adjacency = REVERSE_DIR(junction_dir)
var/turf/neighbor_turf = get_step(src, turned_adjacency & (NORTH|SOUTH))
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, offset_spokesman = src, plane = FLOOR_PLANE)
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
neighbor_turf = get_step(src, turned_adjacency & (EAST|WEST))
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
neighbor_turf = get_step(src, turned_adjacency)
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
neighbor_turf = get_step(src, turned_adjacency & (EAST|WEST))
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
neighbor_turf = get_step(src, turned_adjacency)
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
if(!get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency)) //if all else fails, ask our own turf
underlay_appearance.icon = DEFAULT_UNDERLAY_ICON
underlay_appearance.icon_state = DEFAULT_UNDERLAY_ICON_STATE
underlays += underlay_appearance
if(!get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency)) //if all else fails, ask our own turf
underlay_appearance.icon = DEFAULT_UNDERLAY_ICON
underlay_appearance.icon_state = DEFAULT_UNDERLAY_ICON_STATE
underlays += underlay_appearance
else
icon_state = "[base_icon_state]-[smoothing_junction]"
/turf/open/floor/set_smoothed_icon_state(new_junction)
if(broken || burnt)
@@ -521,5 +531,3 @@ DEFINE_BITFIELD(smoothing_junction, list(
#undef DEFAULT_UNDERLAY_ICON
#undef DEFAULT_UNDERLAY_ICON_STATE
#undef SET_ADJ_IN_DIR
+1 -4
View File
@@ -32,16 +32,13 @@ SUBSYSTEM_DEF(icon_smooth)
can_fire = FALSE
/datum/controller/subsystem/icon_smooth/Initialize()
smooth_zlevel(1, TRUE)
smooth_zlevel(2, TRUE)
var/list/queue = smooth_queue
smooth_queue = list()
while(length(queue))
var/atom/smoothing_atom = queue[length(queue)]
queue.len--
if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED) || smoothing_atom.z <= 2)
if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED) || !smoothing_atom.z)
continue
smoothing_atom.smooth_icon()
CHECK_TICK