Shroud, access ProjectedCellLayer by array index. Shroud.touchedCount to avoid Tick updates.
Shroud, access ProjectedCellLayer by array index over PPos index.
Performance improvement. Avoid the multiple PPos to array index
conversions in the same method call by calculating the cell
layer index once.
Background:
`Shroud.Tick` and `ProjectedCellLayer.Index(PPos puv)` shows up
in profile reports as one of the most expensive methods
(9% of CPU time).
In `Shroud.Tick` calls `ProjectedCellLayer.Index(PPos puv)` multiple
times for the same or different cell layers of the same dimension.
Improvement:
Benchmark results show an 0.5ms mean improvement in tick
time and 0.3 improvement in render time -
on a replay map of 1.12 min of play at max speed.
Render time:
render222052(bleed) render221934(this commit)
count 8144.000000 8144.000000
mean 11.410075 11.470100
std 5.004876 4.731463
min 3.450700 3.638400
25% 7.409100 7.015900
50% 12.410600 12.435900
75% 13.998100 14.242900
max 149.036200 149.656500
Tick time:
tick_time222043(bleed) tick_time221923(this commit)
count 2366.000000 2366.000000
mean 4.762923 4.275833
std 3.240976 3.206362
min 0.263900 1.653600
25% 4.145375 3.668600
50% 4.779350 4.240050
75% 5.232575 4.611775
max 85.751800 87.387100
Shroud.touchedCount to avoid Tick updates if no cells touched.
Avoids iterating over all map cells of the `touched` cell layer.
Tick time improvement of 40%+ - during at least the first two
minutes of gameplay.
During the first minutes of a game - out of every 1000 ticks
only 10-100 result in the Shroud - of any player - to be touched.
For certains player types (Neutral, Creep) less Shroud updates
are expected throughout a complete game.
Throughout a complete game human/AI players can also have no
Shroud touches during certain Ticks.
This commit is contained in:
@@ -22,11 +22,24 @@ namespace OpenRA
|
||||
: base(gridType, size) { }
|
||||
|
||||
// Resolve an array index from map coordinates.
|
||||
int Index(PPos uv)
|
||||
public int Index(PPos uv)
|
||||
{
|
||||
return uv.V * Size.Width + uv.U;
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return entries[index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
entries[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the layer contents using projected map coordinates.</summary>
|
||||
public T this[PPos uv]
|
||||
{
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace OpenRA.Traits
|
||||
readonly ProjectedCellLayer<short> generatedShroudCount;
|
||||
readonly ProjectedCellLayer<bool> explored;
|
||||
readonly ProjectedCellLayer<bool> touched;
|
||||
bool anyCellTouched;
|
||||
|
||||
// Per-cell cache of the resolved cell type (shroud/fog/visible)
|
||||
readonly ProjectedCellLayer<ShroudCellType> resolvedType;
|
||||
@@ -142,6 +143,7 @@ namespace OpenRA.Traits
|
||||
generatedShroudCount = new ProjectedCellLayer<short>(map);
|
||||
explored = new ProjectedCellLayer<bool>(map);
|
||||
touched = new ProjectedCellLayer<bool>(map);
|
||||
anyCellTouched = true;
|
||||
|
||||
// Defaults to 0 = Shroud
|
||||
resolvedType = new ProjectedCellLayer<ShroudCellType>(map);
|
||||
@@ -159,31 +161,42 @@ namespace OpenRA.Traits
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
if (!anyCellTouched)
|
||||
return;
|
||||
|
||||
anyCellTouched = false;
|
||||
|
||||
if (OnShroudChanged == null)
|
||||
return;
|
||||
|
||||
foreach (var puv in map.ProjectedCells)
|
||||
{
|
||||
if (!touched[puv])
|
||||
var index = touched.Index(puv);
|
||||
if (!touched[index])
|
||||
continue;
|
||||
|
||||
touched[puv] = false;
|
||||
touched[index] = false;
|
||||
|
||||
var type = ShroudCellType.Shroud;
|
||||
|
||||
if (explored[puv] && (!shroudGenerationEnabled || generatedShroudCount[puv] == 0 || visibleCount[puv] > 0))
|
||||
if (explored[index])
|
||||
{
|
||||
var count = visibleCount[puv];
|
||||
if (passiveVisibilityEnabled)
|
||||
count += passiveVisibleCount[puv];
|
||||
var count = visibleCount[index];
|
||||
if (!shroudGenerationEnabled || count > 0 || generatedShroudCount[index] == 0)
|
||||
{
|
||||
if (passiveVisibilityEnabled)
|
||||
count += passiveVisibleCount[index];
|
||||
|
||||
type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog;
|
||||
type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog;
|
||||
}
|
||||
}
|
||||
|
||||
var oldResolvedType = resolvedType[puv];
|
||||
resolvedType[puv] = type;
|
||||
var oldResolvedType = resolvedType[index];
|
||||
if (type != oldResolvedType)
|
||||
{
|
||||
resolvedType[index] = type;
|
||||
OnShroudChanged(puv);
|
||||
}
|
||||
}
|
||||
|
||||
Hash = Sync.HashPlayer(self.Owner) + self.World.WorldTick;
|
||||
@@ -231,21 +244,23 @@ namespace OpenRA.Traits
|
||||
if (!map.Contains(puv))
|
||||
continue;
|
||||
|
||||
touched[puv] = true;
|
||||
var index = touched.Index(puv);
|
||||
touched[index] = true;
|
||||
anyCellTouched = true;
|
||||
switch (type)
|
||||
{
|
||||
case SourceType.PassiveVisibility:
|
||||
passiveVisibilityEnabled = true;
|
||||
passiveVisibleCount[puv]++;
|
||||
explored[puv] = true;
|
||||
passiveVisibleCount[index]++;
|
||||
explored[index] = true;
|
||||
break;
|
||||
case SourceType.Visibility:
|
||||
visibleCount[puv]++;
|
||||
explored[puv] = true;
|
||||
visibleCount[index]++;
|
||||
explored[index] = true;
|
||||
break;
|
||||
case SourceType.Shroud:
|
||||
shroudGenerationEnabled = true;
|
||||
generatedShroudCount[puv]++;
|
||||
generatedShroudCount[index]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -261,17 +276,19 @@ namespace OpenRA.Traits
|
||||
// Cells outside the visible bounds don't increment visibleCount
|
||||
if (map.Contains(puv))
|
||||
{
|
||||
touched[puv] = true;
|
||||
var index = touched.Index(puv);
|
||||
touched[index] = true;
|
||||
anyCellTouched = true;
|
||||
switch (state.Type)
|
||||
{
|
||||
case SourceType.PassiveVisibility:
|
||||
passiveVisibleCount[puv]--;
|
||||
passiveVisibleCount[index]--;
|
||||
break;
|
||||
case SourceType.Visibility:
|
||||
visibleCount[puv]--;
|
||||
visibleCount[index]--;
|
||||
break;
|
||||
case SourceType.Shroud:
|
||||
generatedShroudCount[puv]--;
|
||||
generatedShroudCount[index]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -284,10 +301,15 @@ namespace OpenRA.Traits
|
||||
{
|
||||
foreach (var puv in cells)
|
||||
{
|
||||
if (map.Contains(puv) && !explored[puv])
|
||||
if (map.Contains(puv))
|
||||
{
|
||||
touched[puv] = true;
|
||||
explored[puv] = true;
|
||||
var index = touched.Index(puv);
|
||||
if (!explored[index])
|
||||
{
|
||||
touched[index] = true;
|
||||
anyCellTouched = true;
|
||||
explored[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,10 +321,12 @@ namespace OpenRA.Traits
|
||||
|
||||
foreach (var puv in map.ProjectedCells)
|
||||
{
|
||||
if (!explored[puv] && s.explored[puv])
|
||||
var index = touched.Index(puv);
|
||||
if (!explored[index] && s.explored[index])
|
||||
{
|
||||
touched[puv] = true;
|
||||
explored[puv] = true;
|
||||
touched[index] = true;
|
||||
anyCellTouched = true;
|
||||
explored[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,10 +335,12 @@ namespace OpenRA.Traits
|
||||
{
|
||||
foreach (var puv in map.ProjectedCells)
|
||||
{
|
||||
if (!explored[puv])
|
||||
var index = touched.Index(puv);
|
||||
if (!explored[index])
|
||||
{
|
||||
touched[puv] = true;
|
||||
explored[puv] = true;
|
||||
touched[index] = true;
|
||||
anyCellTouched = true;
|
||||
explored[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,9 +349,12 @@ namespace OpenRA.Traits
|
||||
{
|
||||
foreach (var puv in map.ProjectedCells)
|
||||
{
|
||||
touched[puv] = true;
|
||||
explored[puv] = (visibleCount[puv] + passiveVisibleCount[puv]) > 0;
|
||||
var index = touched.Index(puv);
|
||||
touched[index] = true;
|
||||
explored[index] = (visibleCount[index] + passiveVisibleCount[index]) > 0;
|
||||
}
|
||||
|
||||
anyCellTouched = true;
|
||||
}
|
||||
|
||||
public bool IsExplored(WPos pos)
|
||||
|
||||
Reference in New Issue
Block a user