Files
o3de/Gems/PhysX/Code/Tests/Benchmarks/PhysXRigidBodyBenchmarks.cpp
T
Esteban Papp 1f9b284de2 Merge branch 'development' into cmake/SPEC-7179
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

# Conflicts:
#	Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.h
#	Code/Editor/Plugins/EditorCommon/EditorCommon_precompiled.h
#	Code/Editor/Plugins/EditorCommon/stdafx.cpp
#	Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h
#	Code/Editor/Plugins/PerforcePlugin/PerforcePlugin_precompiled.h
#	Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.h
#	Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.h
#	Code/Tools/AssetProcessor/native/precompiled.h
#	Code/Tools/Standalone/StandaloneTools_precompiled.h
#	Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.h
#	Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.h
#	Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/Mac/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/iOS/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.h
#	Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake
#	Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.h
#	Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Android/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Linux/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Mac/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Windows/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.h
#	Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
#	Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake
#	Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h
#	Gems/Blast/Code/Source/StdAfx.cpp
#	Gems/Camera/Code/Source/Camera_precompiled.h
#	Gems/EMotionFX/Code/Source/EMotionFX_precompiled.h
#	Gems/FastNoise/Code/Source/FastNoise_precompiled.h
#	Gems/Gestures/Code/Source/Gestures_precompiled.h
#	Gems/GradientSignal/Code/Source/GradientSignal_precompiled.h
#	Gems/GraphCanvas/Code/precompiled.h
#	Gems/ImGui/Code/Source/ImGui_precompiled.h
#	Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.h
#	Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.h
#	Gems/LmbrCentral/Code/Tests/ShapeGeometryUtilTest.cpp
#	Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.h
#	Gems/LyShine/Code/Source/Animation/LyShine_precompiled.h
#	Gems/LyShine/Code/Source/LyShine_precompiled.h
#	Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.h
#	Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.h
#	Gems/Maestro/Code/Source/Maestro_precompiled.h
#	Gems/MessagePopup/Code/Source/MessagePopup_precompiled.h
#	Gems/Metastream/Code/Source/Metastream_precompiled.h
#	Gems/Microphone/Code/Source/Microphone_precompiled.h
#	Gems/Multiplayer/Code/Source/Multiplayer_precompiled.h
#	Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.h
#	Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.h
#	Gems/PhysX/Code/Source/PhysX_precompiled.h
#	Gems/PhysX/Code/physx_unsupported_files.cmake
#	Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.h
#	Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.h
#	Gems/ScriptCanvas/Code/Editor/precompiled.h
#	Gems/ScriptCanvas/Code/Source/precompiled.h
#	Gems/ScriptCanvasDeveloper/Code/Source/precompiled.h
#	Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.h
#	Gems/ScriptEvents/Code/Source/precompiled.h
#	Gems/ScriptEvents/Code/Tests/Editor/EditorTests.cpp
#	Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.h
#	Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.h
#	Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.h
#	Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.h
#	Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.h
#	Gems/SurfaceData/Code/Source/SurfaceData_precompiled.h
#	Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.h
#	Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.h
#	Gems/Twitch/Code/Source/Twitch_precompiled.h
#	Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBox_precompiled.h
2021-07-16 15:42:37 -07:00

505 lines
24 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifdef HAVE_BENCHMARK
#include <benchmark/benchmark.h>
#include <AzTest/AzTest.h>
#include <AzFramework/Physics/Collision/CollisionEvents.h>
#include <AzFramework/Physics/Common/PhysicsEvents.h>
#include <Benchmarks/PhysXBenchmarksUtilities.h>
#include <Benchmarks/PhysXBenchmarksCommon.h>
#include <Benchmarks/PhysXBenchmarkWashingMachine.h>
#include <PhysXTestCommon.h>
#include <PhysXTestUtil.h>
namespace PhysX::Benchmarks
{
namespace RigidBodyConstants
{
//! Controls the simulation length of the test. 30secs at 60fps
static const int GameFramesToSimulate = 1800;
//! The size of safe the test region, used for spawning Rigid bodies
static const float TestRadius = 250.0f;
//! The size of the test terrain
static const float TerrainSize = 1000.0f;
//! Decide if CCD should be on/off for the following tests
static const bool CCDEnabled = true;
//! Constant seed to use with random number generation
static const long long RandGenSeed = 8010412111588; //(Number generated by concatenating 'PhysX' ascii character codes (80 104 121 115 88).
//! Constants for setting up the washing machine
namespace WashingMachine
{
static const float CylinderHeight = 500.0f;
static const float BladeRPM = 10.0f;
} // namespace WashingMachine
//! Constants for setting up the Rigid Bodies
namespace RigidBodys
{
static const float BoxSize = 5.0f;
//! Default starting value of Entity Ids for rigid bodies
static const AZ::u64 RigidBodyEntityIdStart = 2000u;
}
//! Settings used to setup each benchmark
namespace BenchmarkSettings
{
//! Values passed to benchmark to select the number of rigid bodies to spawn during each test
//! Current values will run tests between StartRange to EndRange (inclusive), multiplying by RangeMultiplier each step.
static const int StartRange = 128;
static const int EndRange = 8192;
static const int RangeMultipler = 2;
//!Flags to adjust how the collision handlers benchmark runs
static const int AllCollisionHanders = 0; // create the same number of handlers as rigid bodies
static const int HalfCollisionHandlers = 1; // create half the number of handlers as rigid bodies
static const int NoCollisionHandlers = 2; // create the no handlers
//! Number of iterations for each test
static const int NumIterations = 3;
} // namespace BenchmarkRange
} // namespace RigidBodyConstants
namespace Utils
{
//! Object that will connect to the collision notification bus of the provided entity id
struct SimulatedBodyCollisionHandler
{
SimulatedBodyCollisionHandler(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle)
: m_onCollisionBeginHandler(
[this]([[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle,
[[maybe_unused]] const AzPhysics::CollisionEvent& event)
{
m_beginCount++;
})
, m_onCollisionPersistHandler(
[this]([[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle,
[[maybe_unused]] const AzPhysics::CollisionEvent& event)
{
m_persistCount++;
})
, m_onCollisionEndHandler(
[this]([[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle,
[[maybe_unused]] const AzPhysics::CollisionEvent& event)
{
m_endCount++;
})
{
AzPhysics::SimulatedBodyEvents::RegisterOnCollisionBeginHandler(sceneHandle, bodyHandle, m_onCollisionBeginHandler);
AzPhysics::SimulatedBodyEvents::RegisterOnCollisionBeginHandler(sceneHandle, bodyHandle, m_onCollisionPersistHandler);
AzPhysics::SimulatedBodyEvents::RegisterOnCollisionBeginHandler(sceneHandle, bodyHandle, m_onCollisionEndHandler);
}
SimulatedBodyCollisionHandler(SimulatedBodyCollisionHandler&& other)
{
m_onCollisionBeginHandler = AZStd::move(other.m_onCollisionBeginHandler);
m_onCollisionPersistHandler = AZStd::move(other.m_onCollisionPersistHandler);
m_onCollisionEndHandler = AZStd::move(other.m_onCollisionEndHandler);
m_beginCount = other.m_beginCount;
m_persistCount = other.m_persistCount;
m_endCount = other.m_endCount;
}
~SimulatedBodyCollisionHandler()
{
m_onCollisionBeginHandler.Disconnect();
m_onCollisionPersistHandler.Disconnect();
m_onCollisionEndHandler.Disconnect();
}
int m_beginCount = 0;
int m_persistCount = 0;
int m_endCount = 0;
private:
AzPhysics::SimulatedBodyEvents::OnCollisionBegin::Handler m_onCollisionBeginHandler;
AzPhysics::SimulatedBodyEvents::OnCollisionPersist::Handler m_onCollisionPersistHandler;
AzPhysics::SimulatedBodyEvents::OnCollisionEnd::Handler m_onCollisionEndHandler;
};
} // namespace Utils
//! Rigid body performance fixture.
//! Will create a world, and terrain.
class PhysXRigidbodyBenchmarkFixture
: public PhysXBaseBenchmarkFixture
{
public:
virtual void SetUp([[maybe_unused]] const ::benchmark::State &state) override
{
PhysXBaseBenchmarkFixture::SetUpInternal();
//need to get the Physics::System to be able to spawn the rigid bodies
m_system = AZ::Interface<Physics::System>::Get();
m_terrainEntity = PhysX::TestUtils::CreateFlatTestTerrain(m_testSceneHandle, RigidBodyConstants::TerrainSize, RigidBodyConstants::TerrainSize);
}
virtual void TearDown([[maybe_unused]] const ::benchmark::State &state) override
{
m_terrainEntity = nullptr;
PhysXBaseBenchmarkFixture::TearDownInternal();
}
protected:
// PhysXBaseBenchmarkFixture Interface ---------
AzPhysics::SceneConfiguration GetDefaultSceneConfiguration() override
{
AzPhysics::SceneConfiguration sceneConfig = AzPhysics::SceneConfiguration::CreateDefault();
sceneConfig.m_enableCcd = RigidBodyConstants::CCDEnabled;
return sceneConfig;
}
// PhysXBaseBenchmarkFixture Interface ---------
Physics::System *m_system;
EntityPtr m_terrainEntity;
};
//! BM_RigidBody_AtRest - This test will spawn the requested number of rigid bodies and place them near the ground
//! and the rigid bodies will go 'asleep'
//! The test will run the simulation for ~1800 game frames at 60fps.
BENCHMARK_DEFINE_F(PhysXRigidbodyBenchmarkFixture, BM_RigidBody_AtRest)(benchmark::State& state)
{
//get the request number of rigid bodies and prepare to spawn them
const int numRigidBodies = static_cast<int>(state.range(0));
//common settings for each rigid body
const float boxSize = 5.0f;
const float boxSizeWithSpacing = RigidBodyConstants::RigidBodys::BoxSize + 2.0f;
const int boxesPerCol = static_cast<const int>(RigidBodyConstants::TerrainSize / boxSizeWithSpacing) - 1;
int spawnColIdx = 0;
int spawnRowIdx = 0;
//function to generate the rigid bodies position / orientation / mass
Utils::GenerateSpawnPositionFuncPtr posGenerator = [boxSizeWithSpacing, boxesPerCol, &spawnColIdx, &spawnRowIdx]([[maybe_unused]] int idx) -> const AZ::Vector3 {
const float x = boxSizeWithSpacing + (boxSizeWithSpacing * spawnColIdx);
const float y = boxSizeWithSpacing + (boxSizeWithSpacing * spawnRowIdx);
const float z = RigidBodyConstants::RigidBodys::BoxSize / 2.0f;
//advance to the next position to spawn the next rigid body
spawnColIdx++;
if (spawnColIdx >= boxesPerCol)
{
spawnColIdx = 0;
spawnRowIdx++;
}
return AZ::Vector3(x, y, z);
};
auto boxShapeConfiguration = AZStd::make_shared<Physics::BoxShapeConfiguration>(AZ::Vector3(RigidBodyConstants::RigidBodys::BoxSize));
Utils::GenerateColliderFuncPtr colliderGenerator = [&boxShapeConfiguration]([[maybe_unused]] int idx)
{
return boxShapeConfiguration;
};
//spawn the rigid bodies
AzPhysics::SimulatedBodyHandleList rigidBodies = Utils::CreateRigidBodies(numRigidBodies, m_defaultScene,
RigidBodyConstants::CCDEnabled, &colliderGenerator, &posGenerator);
//setup the sub tick tracker
Utils::PrePostSimulationEventHandler subTickTracker;
subTickTracker.Start(m_defaultScene);
//setup the frame timer tracker
Types::TimeList tickTimes;
for (auto _ : state)
{
for (AZ::u32 i = 0; i < RigidBodyConstants::GameFramesToSimulate; i++)
{
auto start = AZStd::chrono::system_clock::now();
StepScene1Tick(DefaultTimeStep);
//time each physics tick and store it to analyze
auto tickElapsedMilliseconds = Types::double_milliseconds(AZStd::chrono::system_clock::now() - start);
tickTimes.emplace_back(tickElapsedMilliseconds.count());
}
}
subTickTracker.Stop();
//object clean up
m_defaultScene->RemoveSimulatedBodies(rigidBodies);
rigidBodies.clear();
//sort the frame times and get the P50, P90, P99 percentiles
Utils::ReportFramePercentileCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
Utils::ReportFrameStandardDeviationAndMeanCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
}
//! BM_RigidBody_MovingAndColliding - This test will create the physics washing machine, a cylinder with a spinning blade where
//! it will spawn the requested number of rigid bodies above the machine and let them fall into a spinning blade.
//! The test will run the simulation for ~1800 game frames at 60fps.
BENCHMARK_DEFINE_F(PhysXRigidbodyBenchmarkFixture, BM_RigidBody_MovingAndColliding)(benchmark::State &state)
{
//setup some pieces for the test
AZ::SimpleLcgRandom rand;
rand.SetSeed(RigidBodyConstants::RandGenSeed);
//Create a washing machine of physx objects. This is a cylinder with a spinning blade that rigid bodies are placed inside
const AZ::Vector3 washingMachineCentre(500.0f, 500.0f, 1.0f);
WashingMachine washingMachine;
washingMachine.SetupWashingMachine(
m_testSceneHandle, RigidBodyConstants::TestRadius, RigidBodyConstants::WashingMachine::CylinderHeight,
washingMachineCentre, RigidBodyConstants::WashingMachine::BladeRPM);
//get the request number of rigid bodies and prepare to spawn them
const int numRigidBodies = static_cast<int>(state.range(0));
//add the rigid bodies
//function to generate the rigid bodies position / orientation / mass
Utils::GenerateSpawnPositionFuncPtr posGenerator = [washingMachineCentre, &rand](int idx) -> const AZ::Vector3 {
const float spawnArea = (RigidBodyConstants::TestRadius * 1.5f);
const float x = washingMachineCentre.GetX() + (rand.GetRandomFloat() - 0.5f) * spawnArea;
const float y = washingMachineCentre.GetY() + (rand.GetRandomFloat() - 0.5f) * spawnArea;
const float z = washingMachineCentre.GetZ() + RigidBodyConstants::WashingMachine::CylinderHeight + ((RigidBodyConstants::RigidBodys::BoxSize / 2.0f) * idx);
return AZ::Vector3(x, y, z);
};
Utils::GenerateSpawnOrientationFuncPtr oriGenerator = [&rand]([[maybe_unused]] int idx) -> AZ::Quaternion {
return AZ::CreateRandomQuaternion(rand);
};
Utils::GenerateMassFuncPtr massGenerator = [&rand]([[maybe_unused]] int idx) -> float {
return rand.GetRandomFloat() * 25.0f + 5.0f;
};
auto boxShapeConfiguration = AZStd::make_shared<Physics::BoxShapeConfiguration>(AZ::Vector3(RigidBodyConstants::RigidBodys::BoxSize));
Utils::GenerateColliderFuncPtr colliderGenerator = [&boxShapeConfiguration]([[maybe_unused]] int idx)
{
return boxShapeConfiguration;
};
//spawn the rigid bodies
AzPhysics::SimulatedBodyHandleList rigidBodies = Utils::CreateRigidBodies(numRigidBodies, m_defaultScene,
RigidBodyConstants::CCDEnabled, &colliderGenerator, &posGenerator, &oriGenerator, &massGenerator);
//setup the sub tick tracker
Utils::PrePostSimulationEventHandler subTickTracker;
subTickTracker.Start(m_defaultScene);
//setup the frame timer tracker
AZStd::vector<double> tickTimes;
tickTimes.reserve(RigidBodyConstants::GameFramesToSimulate);
for (auto _ : state)
{
for (AZ::u32 i = 0; i < RigidBodyConstants::GameFramesToSimulate; i++)
{
auto start = AZStd::chrono::system_clock::now();
StepScene1Tick(DefaultTimeStep);
//time each physics tick and store it to analyze
auto tickElapsedMilliseconds = Types::double_milliseconds(AZStd::chrono::system_clock::now() - start);
tickTimes.emplace_back(tickElapsedMilliseconds.count());
}
}
subTickTracker.Stop();
//object clean up
washingMachine.TearDownWashingMachine();
m_defaultScene->RemoveSimulatedBodies(rigidBodies);
rigidBodies.clear();
//sort the frame times and get the P50, P90, P99 percentiles
Utils::ReportFramePercentileCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
Utils::ReportFrameStandardDeviationAndMeanCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
}
//! Same as the PhysXRigidbodyBenchmarkFixture, adds a world event handler to receive collision events
class PhysXRigidbodyCollisionsBenchmarkFixture
: public PhysXRigidbodyBenchmarkFixture
{
public:
void SetUp(const ::benchmark::State& state) override
{
PhysXRigidbodyBenchmarkFixture::SetUp(state);
m_collisionBeginCount = 0;
m_collisionPersistCount = 0;
m_collisionEndCount = 0;
m_onSceneCollisionHandler = AzPhysics::SceneEvents::OnSceneCollisionsEvent::Handler(
[this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
const AzPhysics::CollisionEventList& collisionData)
{
//count the events
for (const auto& collisionEvent : collisionData)
{
switch (collisionEvent.m_type)
{
case AzPhysics::CollisionEvent::Type::Begin:
m_collisionBeginCount++;
break;
case AzPhysics::CollisionEvent::Type::Persist:
m_collisionPersistCount++;
break;
case AzPhysics::CollisionEvent::Type::End:
m_collisionEndCount++;
break;
}
}
}
);
m_defaultScene->RegisterSceneCollisionEventHandler(m_onSceneCollisionHandler);
}
void TearDown(const ::benchmark::State& state) override
{
m_onSceneCollisionHandler.Disconnect();
PhysXRigidbodyBenchmarkFixture::TearDown(state);
}
protected:
// Collision counters to track and report the number of events
int m_collisionBeginCount;
int m_collisionPersistCount;
int m_collisionEndCount;
AzPhysics::SceneEvents::OnSceneCollisionsEvent::Handler m_onSceneCollisionHandler;
};
//! BM_RigidBody_MovingAndColliding_CollisionHandlers - Runs that same benchmark as BM_RigidBody_MovingAndColliding, under a different fixture that adds world event handler for collisions
//! Will have an equal number of Collision Handlers and rigid bodies. Not all rigid bodies will get a handler, some will have multiple.
//! The test will run the simulation for ~1800 game frames at 60fps.
BENCHMARK_DEFINE_F(PhysXRigidbodyCollisionsBenchmarkFixture, BM_RigidBody_MovingAndColliding_CollisionHandlers)(benchmark::State& state)
{
//setup some pieces for the test
AZ::SimpleLcgRandom rand;
rand.SetSeed(RigidBodyConstants::RandGenSeed);
//Create a washing machine of physx objects. This is a cylinder with a spinning blade that rigid bodies are placed inside
const AZ::Vector3 washingMachineCentre(500.0f, 500.0f, 1.0f);
WashingMachine washingMachine;
washingMachine.SetupWashingMachine(
m_testSceneHandle, RigidBodyConstants::TestRadius, RigidBodyConstants::WashingMachine::CylinderHeight,
washingMachineCentre, RigidBodyConstants::WashingMachine::BladeRPM);
//get the request number of rigid bodies and prepare to spawn them
const int numRigidBodies = static_cast<int>(state.range(0));
//add the rigid bodies
//function to generate the rigid bodies position / orientation / mass
Utils::GenerateSpawnPositionFuncPtr posGenerator = [washingMachineCentre, &rand](int idx) -> const AZ::Vector3 {
const float u = std::sqrt(rand.GetRandomFloat());
const float theta = AZ::Constants::TwoPi * rand.GetRandomFloat();
const float x = washingMachineCentre.GetX() + RigidBodyConstants::TestRadius * u * std::sin(theta);
const float y = washingMachineCentre.GetY() + RigidBodyConstants::TestRadius * u * std::cos(theta);
const float z = washingMachineCentre.GetZ() + RigidBodyConstants::WashingMachine::CylinderHeight + ((RigidBodyConstants::RigidBodys::BoxSize / 2.0f) * idx);
return AZ::Vector3(x, y, z);
};
Utils::GenerateSpawnOrientationFuncPtr oriGenerator = [&rand]([[maybe_unused]] int idx) -> AZ::Quaternion {
return AZ::CreateRandomQuaternion(rand);
};
Utils::GenerateMassFuncPtr massGenerator = [&rand]([[maybe_unused]] int idx) -> float {
return rand.GetRandomFloat() * 25.0f + 5.0f;
};
Utils::GenerateEntityIdFuncPtr entityIdGenerator = [&rand](int idx) -> AZ::EntityId {
return AZ::EntityId(static_cast<AZ::u64>(idx) + RigidBodyConstants::RigidBodys::RigidBodyEntityIdStart);
};
auto boxShapeConfiguration = AZStd::make_shared<Physics::BoxShapeConfiguration>(AZ::Vector3(RigidBodyConstants::RigidBodys::BoxSize));
Utils::GenerateColliderFuncPtr colliderGenerator = [&boxShapeConfiguration]([[maybe_unused]] int idx)
{
return boxShapeConfiguration;
};
//spawn the rigid bodies
AzPhysics::SimulatedBodyHandleList rigidBodies = Utils::CreateRigidBodies(numRigidBodies, m_defaultScene,
RigidBodyConstants::CCDEnabled, &colliderGenerator, &posGenerator, &oriGenerator, &massGenerator);
//create the collision handlers
AZStd::vector<Utils::SimulatedBodyCollisionHandler> collisionHandlers;
int numberCollisionHandlers = 0;
if (static_cast<int>(state.range(1)) == RigidBodyConstants::BenchmarkSettings::AllCollisionHanders)
{
numberCollisionHandlers = numRigidBodies;
}
else if (static_cast<int>(state.range(1)) == RigidBodyConstants::BenchmarkSettings::HalfCollisionHandlers)
{
numberCollisionHandlers = numRigidBodies / 2;
}
collisionHandlers.reserve(numberCollisionHandlers);
for (int i = 0; i < numberCollisionHandlers; i++)
{
const AZ::u64 randIndex = rand.Getu64Random() % numRigidBodies; //randomly select the offset.
collisionHandlers.emplace_back(m_testSceneHandle, rigidBodies[randIndex]);
}
//setup the sub tick tracker
Utils::PrePostSimulationEventHandler subTickTracker;
subTickTracker.Start(m_defaultScene);
//setup the frame timer tracker
AZStd::vector<double> tickTimes;
tickTimes.reserve(RigidBodyConstants::GameFramesToSimulate);
for (auto _ : state)
{
for (AZ::u32 i = 0; i < RigidBodyConstants::GameFramesToSimulate; i++)
{
auto start = AZStd::chrono::system_clock::now();
StepScene1Tick(DefaultTimeStep);
//time each physics tick and store it to analyze
auto tickElapsedMilliseconds = Types::double_milliseconds(AZStd::chrono::system_clock::now() - start);
tickTimes.emplace_back(tickElapsedMilliseconds.count());
}
}
subTickTracker.Stop();
//object clean up
collisionHandlers.clear();
washingMachine.TearDownWashingMachine();
m_defaultScene->RemoveSimulatedBodies(rigidBodies);
rigidBodies.clear();
//sort the frame times and get the P50, P90, P99 percentiles
Utils::ReportFramePercentileCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
Utils::ReportFrameStandardDeviationAndMeanCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
//add the collision counts
state.counters["Collisions-Begin"] = static_cast<double>(m_collisionBeginCount);
state.counters["Collisions-Persist"] = static_cast<double>(m_collisionPersistCount);
state.counters["Collisions-End"] = static_cast<double>(m_collisionEndCount);
}
BENCHMARK_REGISTER_F(PhysXRigidbodyBenchmarkFixture, BM_RigidBody_AtRest)
->RangeMultiplier(RigidBodyConstants::BenchmarkSettings::RangeMultipler)
->Range(RigidBodyConstants::BenchmarkSettings::StartRange, RigidBodyConstants::BenchmarkSettings::EndRange)
->Unit(benchmark::kMillisecond)
->Iterations(RigidBodyConstants::BenchmarkSettings::NumIterations)
;
BENCHMARK_REGISTER_F(PhysXRigidbodyBenchmarkFixture, BM_RigidBody_MovingAndColliding)
->RangeMultiplier(RigidBodyConstants::BenchmarkSettings::RangeMultipler)
->Range(RigidBodyConstants::BenchmarkSettings::StartRange, RigidBodyConstants::BenchmarkSettings::EndRange)
->Unit(benchmark::kMillisecond)
->Iterations(RigidBodyConstants::BenchmarkSettings::NumIterations)
;
BENCHMARK_REGISTER_F(PhysXRigidbodyCollisionsBenchmarkFixture, BM_RigidBody_MovingAndColliding_CollisionHandlers)
->RangeMultiplier(RigidBodyConstants::BenchmarkSettings::RangeMultipler)
->Ranges({ {RigidBodyConstants::BenchmarkSettings::StartRange, RigidBodyConstants::BenchmarkSettings::EndRange}, {RigidBodyConstants::BenchmarkSettings::AllCollisionHanders, RigidBodyConstants::BenchmarkSettings::AllCollisionHanders} })
->Unit(benchmark::kMillisecond)
->Iterations(RigidBodyConstants::BenchmarkSettings::NumIterations)
;
BENCHMARK_REGISTER_F(PhysXRigidbodyCollisionsBenchmarkFixture, BM_RigidBody_MovingAndColliding_CollisionHandlers)
->RangeMultiplier(RigidBodyConstants::BenchmarkSettings::RangeMultipler)
->Ranges({ {RigidBodyConstants::BenchmarkSettings::StartRange, RigidBodyConstants::BenchmarkSettings::EndRange}, {RigidBodyConstants::BenchmarkSettings::HalfCollisionHandlers, RigidBodyConstants::BenchmarkSettings::HalfCollisionHandlers} })
->Unit(benchmark::kMillisecond)
->Iterations(RigidBodyConstants::BenchmarkSettings::NumIterations)
;
BENCHMARK_REGISTER_F(PhysXRigidbodyCollisionsBenchmarkFixture, BM_RigidBody_MovingAndColliding_CollisionHandlers)
->RangeMultiplier(RigidBodyConstants::BenchmarkSettings::RangeMultipler)
->Ranges({ {RigidBodyConstants::BenchmarkSettings::StartRange, RigidBodyConstants::BenchmarkSettings::EndRange}, {RigidBodyConstants::BenchmarkSettings::NoCollisionHandlers, RigidBodyConstants::BenchmarkSettings::NoCollisionHandlers} })
->Unit(benchmark::kMillisecond)
->Iterations(RigidBodyConstants::BenchmarkSettings::NumIterations)
;
} // namespace PhysX::Benchmarks
#endif