Misc SurfaceData Optimizations (#7299)

* Misc SurfaceData Optimizations.
This includes a few different optimizations found while trying to make the bulk query APIs faster:
* Switches mutexes over to shared_lock to optimize for the multi-reader-single-writer pattern
* Surface provider point creation now uses a pre-created set of masks to initialize with, and uses std::move() to move the created point into the output list instead of copying it.
* Splits CombineSortAndFilterNeightboringPoints so that the FilterPoints() can occur separately and efficiently with erase/remove_if, and avoids making a copy of the output points.
* Optimized SurfaceDataShapeComponent::ModifySurfacePoints
* Fixed potential bug where the sort wasn't stable since it only compared the Z value, and could have produced unexpected results for differing points with the exact same Z value.
* Fixed up a couple small bugs and missing checks in the unit tests

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

* Fixed syntax on unit tests.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2022-02-01 10:44:14 -06:00
committed by GitHub
parent ff4529fc60
commit 3f63cf3546
12 changed files with 221 additions and 181 deletions
@@ -132,6 +132,7 @@ namespace SurfaceData
Physics::ColliderComponentEventBus::Handler::BusConnect(GetEntityId());
// Update the cached collider data and bounds, then register the surface data provider / modifier
AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f, m_newPointWeights);
UpdateColliderData();
}
@@ -157,7 +158,7 @@ namespace SurfaceData
// Clear the cached mesh data
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
m_colliderBounds = AZ::Aabb::CreateNull();
}
}
@@ -184,7 +185,7 @@ namespace SurfaceData
bool SurfaceDataColliderComponent::DoRayTrace(const AZ::Vector3& inPosition, bool queryPointOnly, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
// test AABB as first pass to claim the point
const AZ::Vector3 testPosition = AZ::Vector3(
@@ -240,17 +241,14 @@ namespace SurfaceData
point.m_entityId = GetEntityId();
point.m_position = hitPosition;
point.m_normal = hitNormal;
for (auto& tag : m_configuration.m_providerTags)
{
point.m_masks[tag] = 1.0f;
}
surfacePointList.push_back(point);
point.m_masks = m_newPointWeights;
surfacePointList.push_back(AZStd::move(point));
}
}
void SurfaceDataColliderComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
if (m_colliderBounds.IsValid() && !m_configuration.m_modifierTags.empty())
{
@@ -308,7 +306,7 @@ namespace SurfaceData
bool colliderValidAfterUpdate = false;
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
colliderValidBeforeUpdate = m_colliderBounds.IsValid();
@@ -12,6 +12,7 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/parallel/shared_mutex.h>
#include <AzFramework/Physics/ColliderComponentBus.h>
#include <SurfaceData/SurfaceDataTypes.h>
@@ -98,7 +99,8 @@ namespace SurfaceData
// cached data
AZStd::atomic_bool m_refresh{ false };
mutable AZStd::recursive_mutex m_cacheMutex;
mutable AZStd::shared_mutex m_cacheMutex;
AZ::Aabb m_colliderBounds = AZ::Aabb::CreateNull();
SurfaceTagWeightMap m_newPointWeights;
};
}
@@ -89,6 +89,7 @@ namespace SurfaceData
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId());
// Update the cached shape data and bounds, then register the surface data provider / modifier
AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f, m_newPointWeights);
UpdateShapeData();
}
@@ -115,7 +116,7 @@ namespace SurfaceData
// Clear the cached shape data
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
m_shapeBounds = AZ::Aabb::CreateNull();
m_shapeBoundsIsValid = false;
}
@@ -143,7 +144,7 @@ namespace SurfaceData
void SurfaceDataShapeComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
if (m_shapeBoundsIsValid)
{
@@ -158,36 +159,35 @@ namespace SurfaceData
point.m_entityId = GetEntityId();
point.m_position = rayOrigin + intersectionDistance * rayDirection;
point.m_normal = AZ::Vector3::CreateAxisZ();
for (auto& tag : m_configuration.m_providerTags)
{
point.m_masks[tag] = 1.0f;
}
surfacePointList.push_back(point);
point.m_masks = m_newPointWeights;
surfacePointList.push_back(AZStd::move(point));
}
}
}
void SurfaceDataShapeComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
{
AZ_PROFILE_FUNCTION(Entity);
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
if (m_shapeBoundsIsValid && !m_configuration.m_modifierTags.empty())
{
const AZ::EntityId entityId = GetEntityId();
for (auto& point : surfacePointList)
{
if (point.m_entityId != entityId && m_shapeBounds.Contains(point.m_position))
LmbrCentral::ShapeComponentRequestsBus::Event(
GetEntityId(),
[entityId, this, &surfacePointList](LmbrCentral::ShapeComponentRequestsBus::Events* shape)
{
bool inside = false;
LmbrCentral::ShapeComponentRequestsBus::EventResult(inside, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::IsPointInside, point.m_position);
if (inside)
for (auto& point : surfacePointList)
{
AddMaxValueForMasks(point.m_masks, m_configuration.m_modifierTags, 1.0f);
if (point.m_entityId != entityId && m_shapeBounds.Contains(point.m_position))
{
bool inside = shape->IsPointInside(point.m_position);
if (inside)
{
AddMaxValueForMasks(point.m_masks, m_configuration.m_modifierTags, 1.0f);
}
}
}
}
}
});
}
}
@@ -228,7 +228,7 @@ namespace SurfaceData
bool shapeValidAfterUpdate = false;
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
shapeValidBeforeUpdate = m_shapeBoundsIsValid;
@@ -11,6 +11,7 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/parallel/shared_mutex.h>
#include <LmbrCentral/Shape/ShapeComponentBus.h>
#include <SurfaceData/SurfaceDataModifierRequestBus.h>
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
@@ -92,9 +93,10 @@ namespace SurfaceData
// cached data
AZStd::atomic_bool m_refresh{ false };
mutable AZStd::recursive_mutex m_cacheMutex;
mutable AZStd::shared_mutex m_cacheMutex;
AZ::Aabb m_shapeBounds = AZ::Aabb::CreateNull();
bool m_shapeBoundsIsValid = false;
static const float s_rayAABBHeightPadding;
SurfaceTagWeightMap m_newPointWeights;
};
}