SurfaceTagWeights optimization (#7436)

* Add comparison operators to SurfaceTagWeight.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Changed AddSurfaceTagWeight to always combine weights.
This simplifies the API a bit and defines the behavior if someone ever tries to add a duplicate tag.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Added benchmarks for measuring the performance-critical APIs.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Changed SurfaceTagWeights to a fixed_vector.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2022-02-07 10:57:39 -06:00
committed by GitHub
parent 58f8cc666c
commit a6ddf4164f
9 changed files with 198 additions and 61 deletions
@@ -259,7 +259,7 @@ namespace SurfaceData
if (DoRayTrace(position, queryPointOnly, hitPosition, hitNormal))
{
// If the query point collides with the volume, add all our modifier tags with a weight of 1.0f.
weights.AddSurfaceWeightsIfGreater(m_configuration.m_modifierTags, 1.0f);
weights.AddSurfaceTagWeights(m_configuration.m_modifierTags, 1.0f);
}
}
});
@@ -179,7 +179,7 @@ namespace SurfaceData
if (m_shapeBounds.Contains(position) && shape->IsPointInside(position))
{
// If the point is inside our shape, add all our modifier tags with a weight of 1.0f.
weights.AddSurfaceWeightsIfGreater(m_configuration.m_modifierTags, 1.0f);
weights.AddSurfaceTagWeights(m_configuration.m_modifierTags, 1.0f);
}
});
});
@@ -14,28 +14,21 @@ namespace SurfaceData
void SurfaceTagWeights::AssignSurfaceTagWeights(const AzFramework::SurfaceData::SurfaceTagWeightList& weights)
{
m_weights.clear();
m_weights.reserve(weights.size());
for (auto& weight : weights)
{
m_weights.emplace(weight.m_surfaceType, weight.m_weight);
AddSurfaceTagWeight(weight.m_surfaceType, weight.m_weight);
}
}
void SurfaceTagWeights::AssignSurfaceTagWeights(const SurfaceTagVector& tags, float weight)
{
m_weights.clear();
m_weights.reserve(tags.size());
for (auto& tag : tags)
{
m_weights[tag] = weight;
AddSurfaceTagWeight(tag.operator AZ::Crc32(), weight);
}
}
void SurfaceTagWeights::AddSurfaceTagWeight(const AZ::Crc32 tag, const float value)
{
m_weights[tag] = value;
}
void SurfaceTagWeights::Clear()
{
m_weights.clear();
@@ -52,7 +45,7 @@ namespace SurfaceData
weights.reserve(m_weights.size());
for (auto& weight : m_weights)
{
weights.emplace_back(weight.first, weight.second);
weights.emplace_back(weight);
}
return weights;
}
@@ -65,17 +58,8 @@ namespace SurfaceData
return false;
}
for (auto& weight : m_weights)
{
auto rhsWeight = rhs.m_weights.find(weight.first);
if ((rhsWeight == rhs.m_weights.end()) || (rhsWeight->second != weight.second))
{
return false;
}
}
// All the entries matched, and the lists are the same size, so they're equal.
return true;
// The lists are stored in sorted order, so we can compare every entry in order for equivalence.
return (m_weights == rhs.m_weights);
}
bool SurfaceTagWeights::SurfaceWeightsAreEqual(const AzFramework::SurfaceData::SurfaceTagWeightList& compareWeights) const
@@ -92,7 +76,7 @@ namespace SurfaceData
compareWeights.begin(), compareWeights.end(),
[weight](const AzFramework::SurfaceData::SurfaceTagWeight& compareWeight) -> bool
{
return (weight.first == compareWeight.m_surfaceType) && (weight.second == compareWeight.m_weight);
return (weight == compareWeight);
});
// If we didn't find a match, they're not equal.
@@ -119,9 +103,9 @@ namespace SurfaceData
bool SurfaceTagWeights::HasValidTags() const
{
for (const auto& sourceTag : m_weights)
for (const auto& weight : m_weights)
{
if (sourceTag.first != Constants::s_unassignedTagCrc)
if (weight.m_surfaceType != Constants::s_unassignedTagCrc)
{
return true;
}
@@ -129,9 +113,9 @@ namespace SurfaceData
return false;
}
bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag) const
bool SurfaceTagWeights::HasMatchingTag(AZ::Crc32 sampleTag) const
{
return m_weights.find(sampleTag) != m_weights.end();
return FindTag(sampleTag) != m_weights.end();
}
bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags) const
@@ -147,10 +131,10 @@ namespace SurfaceData
return false;
}
bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag, float weightMin, float weightMax) const
bool SurfaceTagWeights::HasMatchingTag(AZ::Crc32 sampleTag, float weightMin, float weightMax) const
{
auto maskItr = m_weights.find(sampleTag);
return maskItr != m_weights.end() && weightMin <= maskItr->second && weightMax >= maskItr->second;
auto weightEntry = FindTag(sampleTag);
return weightEntry != m_weights.end() && weightMin <= weightEntry->m_weight && weightMax >= weightEntry->m_weight;
}
bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags, float weightMin, float weightMax) const
@@ -166,7 +150,25 @@ namespace SurfaceData
return false;
}
const AzFramework::SurfaceData::SurfaceTagWeight* SurfaceTagWeights::FindTag(AZ::Crc32 tag) const
{
for (auto weightItr = m_weights.begin(); weightItr != m_weights.end(); ++weightItr)
{
if (weightItr->m_surfaceType == tag)
{
// Found the tag, return a pointer to the entry.
return weightItr;
}
else if (weightItr->m_surfaceType > tag)
{
// Our list is stored in sorted order by surfaceType, so early-out if our values get too high.
break;
}
}
// The tag wasn't found, so return end().
return m_weights.end();
}
SurfacePointList::SurfacePointList(AZStd::initializer_list<const AzFramework::SurfaceData::SurfacePoint> surfacePoints)
@@ -192,7 +194,7 @@ namespace SurfaceData
if (m_surfacePositionList[index].IsClose(position) && m_surfaceNormalList[index].IsClose(normal))
{
// consolidate points with similar attributes by adding masks/weights to the similar point instead of adding a new one.
m_surfaceWeightsList[index].AddSurfaceWeightsIfGreater(masks);
m_surfaceWeightsList[index].AddSurfaceTagWeights(masks);
return;
}
else if (m_surfacePositionList[index].GetZ() < position.GetZ())