FastNoise GetValues() specialization (#7009)
* Add comparison operator for use from unit tests. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * First version of FastNoise benchmarks. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Simplified unit tests and added initial benchmarks. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Add GetValue vs GetValues unit test. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Moved Gradient test code into helper files for use from FastNoise. Also added benchmarks for each type of FastNoise so that we can have some comparative values handy. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Specialization for GetValues(). Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
@@ -104,7 +104,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
NAME FastNoise.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
fastnoise_tests_files.cmake
|
||||
fastnoise_editor_tests_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PUBLIC
|
||||
FASTNOISE_EDITOR
|
||||
@@ -120,23 +120,31 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
ly_add_googletest(
|
||||
NAME Gem::FastNoise.Editor.Tests
|
||||
)
|
||||
else()
|
||||
ly_add_target(
|
||||
NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
fastnoise_tests_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Tests
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
Gem::FastNoise.Static
|
||||
Gem::LmbrCentral
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Gem::FastNoise.Tests
|
||||
)
|
||||
endif()
|
||||
|
||||
ly_add_target(
|
||||
NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
fastnoise_tests_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Tests
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
Gem::FastNoise.Static
|
||||
Gem::GradientSignal
|
||||
Gem::GradientSignal.Tests.Static
|
||||
Gem::LmbrCentral
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Gem::FastNoise.Tests
|
||||
)
|
||||
|
||||
ly_add_googlebenchmark(
|
||||
NAME Gem::FastNoise.Benchmarks
|
||||
TARGET Gem::FastNoise.Tests
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -54,6 +54,21 @@ namespace FastNoiseGem
|
||||
return AZ::Edit::PropertyVisibility::Hide;
|
||||
}
|
||||
|
||||
bool FastNoiseGradientConfig::operator==(const FastNoiseGradientConfig& rhs) const
|
||||
{
|
||||
return (m_cellularDistanceFunction == rhs.m_cellularDistanceFunction)
|
||||
&& (m_cellularJitter == rhs.m_cellularJitter)
|
||||
&& (m_cellularReturnType == rhs.m_cellularReturnType)
|
||||
&& (m_fractalType == rhs.m_fractalType)
|
||||
&& (m_frequency == rhs.m_frequency)
|
||||
&& (m_gain == rhs.m_gain)
|
||||
&& (m_interp == rhs.m_interp)
|
||||
&& (m_lacunarity == rhs.m_lacunarity)
|
||||
&& (m_noiseType == rhs.m_noiseType)
|
||||
&& (m_octaves == rhs.m_octaves)
|
||||
&& (m_seed == rhs.m_seed);
|
||||
}
|
||||
|
||||
void FastNoiseGradientConfig::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
@@ -306,7 +321,7 @@ namespace FastNoiseGem
|
||||
|
||||
float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const
|
||||
{
|
||||
AZ::Vector3 uvw = sampleParams.m_position;
|
||||
AZ::Vector3 uvw;
|
||||
bool wasPointRejected = false;
|
||||
|
||||
{
|
||||
@@ -314,13 +329,34 @@ namespace FastNoiseGem
|
||||
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
|
||||
}
|
||||
|
||||
if (!wasPointRejected)
|
||||
// Generator returns a range between [-1, 1], map that to [0, 1]
|
||||
return wasPointRejected ?
|
||||
0.0f :
|
||||
AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void FastNoiseGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
|
||||
{
|
||||
if (positions.size() != outValues.size())
|
||||
{
|
||||
// Generator returns a range between [-1, 1], map that to [0, 1]
|
||||
return AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
|
||||
AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size());
|
||||
return;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
AZ::Vector3 uvw;
|
||||
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
bool wasPointRejected = false;
|
||||
|
||||
m_gradientTransform.TransformPositionToUVW(positions[index], uvw, wasPointRejected);
|
||||
|
||||
// Generator returns a range between [-1, 1], map that to [0, 1]
|
||||
outValues[index] = wasPointRejected ?
|
||||
0.0f :
|
||||
AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TValueType, TValueType FastNoiseGradientConfig::*TConfigMember, void (FastNoise::*TMethod)(TValueType)>
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace FastNoiseGem
|
||||
AZ::u32 GetFrequencyParameterVisbility() const;
|
||||
AZ::u32 GetInterpParameterVisibility() const;
|
||||
|
||||
bool operator==(const FastNoiseGradientConfig& rhs) const;
|
||||
|
||||
int m_seed = 1;
|
||||
float m_frequency = 1.f;
|
||||
FastNoise::Interp m_interp = FastNoise::Interp::Quintic;
|
||||
@@ -90,6 +92,7 @@ namespace FastNoiseGem
|
||||
|
||||
// GradientRequestBus overrides...
|
||||
float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override;
|
||||
void GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const override;
|
||||
|
||||
protected:
|
||||
FastNoiseGradientConfig m_configuration;
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <FastNoiseGradientComponent.h>
|
||||
#include <FastNoiseTest.h>
|
||||
#include <GradientSignalTestHelpers.h>
|
||||
#include <GradientSignal/Components/GradientTransformComponent.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformModifierRequestBus.h>
|
||||
#include <GradientSignal/GradientSampler.h>
|
||||
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class FastNoiseGetValues
|
||||
: public ::benchmark::Fixture
|
||||
{
|
||||
public:
|
||||
void RunGetValueOrGetValuesBenchmark(benchmark::State& state, FastNoise::NoiseType noiseType)
|
||||
{
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
|
||||
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
|
||||
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
|
||||
|
||||
// Set up a FastNoise component with the requested noise type
|
||||
FastNoiseGem::FastNoiseGradientConfig cfg;
|
||||
cfg.m_frequency = 0.01f;
|
||||
cfg.m_noiseType = noiseType;
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
|
||||
|
||||
noiseEntity->Init();
|
||||
noiseEntity->Activate();
|
||||
|
||||
UnitTest::GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, noiseEntity->GetId());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Value)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Value);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::ValueFractal);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Perlin);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::PerlinFractal);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Simplex);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::SimplexFractal);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cellular);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::WhiteNoise);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cubic);
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal)(benchmark::State& state)
|
||||
{
|
||||
RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::CubicFractal);
|
||||
}
|
||||
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Value);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic);
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <EditorFastNoiseGradientComponent.h>
|
||||
#include <FastNoiseTest.h>
|
||||
|
||||
|
||||
class FastNoiseEditorTestApp : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(FastNoiseEditorTestApp, FastNoise_EditorCreateGameEntity)
|
||||
{
|
||||
AZStd::unique_ptr<AZ::Entity> noiseEntity(aznew AZ::Entity("editor_noise_entity"));
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
|
||||
FastNoiseGem::EditorFastNoiseGradientComponent editor;
|
||||
auto* editorBase = static_cast<AzToolsFramework::Components::EditorComponentBase*>(&editor);
|
||||
editorBase->BuildGameEntity(noiseEntity.get());
|
||||
|
||||
// the new game entity's FastNoise component should look like the default one
|
||||
FastNoiseGem::FastNoiseGradientConfig defaultConfig;
|
||||
FastNoiseGem::FastNoiseGradientConfig gameComponentConfig;
|
||||
|
||||
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
ASSERT_TRUE(noiseComp != nullptr);
|
||||
|
||||
// Change a value in the gameComponentConfig just to verify that it got overwritten instead of simply matching the default.
|
||||
gameComponentConfig.m_seed++;
|
||||
noiseComp->WriteOutConfig(&gameComponentConfig);
|
||||
ASSERT_EQ(defaultConfig, gameComponentConfig);
|
||||
}
|
||||
|
||||
// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems.
|
||||
AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment);
|
||||
@@ -10,199 +10,61 @@
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Math/Random.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Script/ScriptContext.h>
|
||||
#include <AzCore/std/chrono/clocks.h>
|
||||
#include <FastNoiseSystemComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <FastNoiseGradientComponent.h>
|
||||
#include <FastNoiseModule.h>
|
||||
#include <FastNoiseTest.h>
|
||||
#include <GradientSignalTestHelpers.h>
|
||||
#include <GradientSignal/Components/GradientTransformComponent.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformModifierRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
|
||||
#include <GradientSignal/GradientSampler.h>
|
||||
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
|
||||
|
||||
class MockGradientTransformComponent
|
||||
: public AZ::Component
|
||||
, private GradientSignal::GradientTransformRequestBus::Handler
|
||||
, private GradientSignal::GradientTransformModifierRequestBus::Handler
|
||||
class FastNoiseTest : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(MockGradientTransformComponent, "{464CF47B-7E10-4E1B-BD06-79BD2AC91399}");
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("GradientTransformService", 0x8c8c5ecc));
|
||||
}
|
||||
static void Reflect([[maybe_unused]] AZ::ReflectContext* context) {}
|
||||
|
||||
MockGradientTransformComponent() = default;
|
||||
~MockGradientTransformComponent() = default;
|
||||
|
||||
// AZ::Component interface
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//// GradientTransformRequestBus
|
||||
const GradientSignal::GradientTransform& GetGradientTransform() const override
|
||||
{
|
||||
return m_gradientTransform;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientTransformModifierRequestBus
|
||||
bool GetAllowReference() const override { return false; }
|
||||
void SetAllowReference([[maybe_unused]] bool value) override {}
|
||||
|
||||
AZ::EntityId GetShapeReference() const override { return AZ::EntityId(); }
|
||||
void SetShapeReference([[maybe_unused]] AZ::EntityId shapeReference) override {}
|
||||
|
||||
bool GetOverrideBounds() const override { return false; }
|
||||
void SetOverrideBounds([[maybe_unused]] bool value) override {}
|
||||
|
||||
AZ::Vector3 GetBounds() const override { return AZ::Vector3(); }
|
||||
void SetBounds([[maybe_unused]] AZ::Vector3 bounds) override {}
|
||||
|
||||
GradientSignal::TransformType GetTransformType() const override { return static_cast<GradientSignal::TransformType>(0); }
|
||||
void SetTransformType([[maybe_unused]] GradientSignal::TransformType type) override {}
|
||||
|
||||
bool GetOverrideTranslate() const override { return false; }
|
||||
void SetOverrideTranslate([[maybe_unused]] bool value) override {}
|
||||
|
||||
AZ::Vector3 GetTranslate() const override { return AZ::Vector3(); }
|
||||
void SetTranslate([[maybe_unused]] AZ::Vector3 translate) override {}
|
||||
|
||||
bool GetOverrideRotate() const override { return false; }
|
||||
void SetOverrideRotate([[maybe_unused]] bool value) override {}
|
||||
|
||||
AZ::Vector3 GetRotate() const override { return AZ::Vector3(); }
|
||||
void SetRotate([[maybe_unused]] AZ::Vector3 rotate) override {}
|
||||
|
||||
bool GetOverrideScale() const override { return false; }
|
||||
void SetOverrideScale([[maybe_unused]] bool value) override {}
|
||||
|
||||
AZ::Vector3 GetScale() const override { return AZ::Vector3(); }
|
||||
void SetScale([[maybe_unused]] AZ::Vector3 scale) override {}
|
||||
|
||||
float GetFrequencyZoom() const override { return false; }
|
||||
void SetFrequencyZoom([[maybe_unused]] float frequencyZoom) override {}
|
||||
|
||||
GradientSignal::WrappingType GetWrappingType() const override { return static_cast<GradientSignal::WrappingType>(0); }
|
||||
void SetWrappingType([[maybe_unused]] GradientSignal::WrappingType type) override {}
|
||||
|
||||
bool GetIs3D() const override { return false; }
|
||||
void SetIs3D([[maybe_unused]] bool value) override {}
|
||||
|
||||
bool GetAdvancedMode() const override { return false; }
|
||||
void SetAdvancedMode([[maybe_unused]] bool value) override {}
|
||||
|
||||
GradientSignal::GradientTransform m_gradientTransform;
|
||||
};
|
||||
|
||||
TEST(FastNoiseTest, ComponentsWithComponentApplication)
|
||||
{
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
|
||||
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
|
||||
appDesc.m_stackRecordLevels = 20;
|
||||
|
||||
AZ::ComponentApplication app;
|
||||
AZ::Entity* systemEntity = app.Create(appDesc);
|
||||
ASSERT_TRUE(systemEntity != nullptr);
|
||||
app.RegisterComponentDescriptor(FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor());
|
||||
systemEntity->CreateComponent<FastNoiseGem::FastNoiseSystemComponent>();
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate();
|
||||
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("fastnoise_entity");
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
app.AddEntity(noiseEntity);
|
||||
|
||||
app.Destroy();
|
||||
ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
class FastNoiseTestApp
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
FastNoiseTestApp()
|
||||
: m_application()
|
||||
, m_systemEntity(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
|
||||
appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL;
|
||||
appDesc.m_stackRecordLevels = 20;
|
||||
|
||||
AZ::ComponentApplication::StartupParameters appStartup;
|
||||
appStartup.m_createStaticModulesCallback =
|
||||
[](AZStd::vector<AZ::Module*>& modules)
|
||||
{
|
||||
modules.emplace_back(new FastNoiseGem::FastNoiseModule);
|
||||
};
|
||||
|
||||
m_systemEntity = m_application.Create(appDesc, appStartup);
|
||||
m_application.RegisterComponentDescriptor(MockGradientTransformComponent::CreateDescriptor());
|
||||
m_systemEntity->Init();
|
||||
m_systemEntity->Activate();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_application.Destroy();
|
||||
}
|
||||
|
||||
AZ::ComponentApplication m_application;
|
||||
AZ::Entity* m_systemEntity;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// testing class to inspect protected data members in the FastNoiseGradientComponent
|
||||
struct FastNoiseGradientComponentTester : public FastNoiseGem::FastNoiseGradientComponent
|
||||
{
|
||||
const FastNoiseGem::FastNoiseGradientConfig& GetConfig() const { return m_configuration; }
|
||||
|
||||
void AssertTrue(const FastNoiseGem::FastNoiseGradientConfig& cfg)
|
||||
{
|
||||
ASSERT_TRUE(m_configuration.m_cellularDistanceFunction == cfg.m_cellularDistanceFunction);
|
||||
ASSERT_TRUE(m_configuration.m_cellularJitter == cfg.m_cellularJitter);
|
||||
ASSERT_TRUE(m_configuration.m_cellularReturnType == cfg.m_cellularReturnType);
|
||||
ASSERT_TRUE(m_configuration.m_fractalType == cfg.m_fractalType);
|
||||
ASSERT_TRUE(m_configuration.m_frequency == cfg.m_frequency);
|
||||
ASSERT_TRUE(m_configuration.m_gain == cfg.m_gain);
|
||||
ASSERT_TRUE(m_configuration.m_interp == cfg.m_interp);
|
||||
ASSERT_TRUE(m_configuration.m_lacunarity == cfg.m_lacunarity);
|
||||
ASSERT_TRUE(m_configuration.m_noiseType == cfg.m_noiseType);
|
||||
ASSERT_TRUE(m_configuration.m_octaves == cfg.m_octaves);
|
||||
ASSERT_TRUE(m_configuration.m_seed == cfg.m_seed);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FastNoiseTestApp, FastNoise_Component)
|
||||
TEST_F(FastNoiseTest, FastNoise_ComponentCreatesSuccessfully)
|
||||
{
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
m_application.AddEntity(noiseEntity);
|
||||
|
||||
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
ASSERT_TRUE(noiseComp != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus)
|
||||
TEST_F(FastNoiseTest, FastNoise_ComponentMatchesConfiguration)
|
||||
{
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
|
||||
FastNoiseGem::FastNoiseGradientConfig cfg;
|
||||
FastNoiseGem::FastNoiseGradientConfig componentConfig;
|
||||
|
||||
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
|
||||
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
|
||||
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
|
||||
|
||||
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
ASSERT_TRUE(noiseComp != nullptr);
|
||||
noiseComp->WriteOutConfig(&componentConfig);
|
||||
ASSERT_EQ(cfg, componentConfig);
|
||||
}
|
||||
|
||||
TEST_F(FastNoiseTest, FastNoise_ComponentEbusWorksSuccessfully)
|
||||
{
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
|
||||
noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
|
||||
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
noiseEntity->CreateComponent<MockGradientTransformComponent>();
|
||||
|
||||
noiseEntity->Init();
|
||||
noiseEntity->Activate();
|
||||
@@ -210,51 +72,39 @@ TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus)
|
||||
GradientSignal::GradientSampleParams params;
|
||||
float sample = -1.0f;
|
||||
|
||||
GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params);
|
||||
GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(),
|
||||
&GradientSignal::GradientRequestBus::Events::GetValue, params);
|
||||
ASSERT_TRUE(sample >= 0.0f);
|
||||
ASSERT_TRUE(sample <= 1.0f);
|
||||
}
|
||||
|
||||
TEST_F(FastNoiseTestApp, FastNoise_ComponentMatchesConfiguration)
|
||||
TEST_F(FastNoiseTest, FastNoise_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
const float shapeHalfBounds = 128.0f;
|
||||
|
||||
AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity");
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
noiseEntity->CreateComponent<AzFramework::TransformComponent>();
|
||||
noiseEntity->CreateComponent<GradientSignal::GradientTransformComponent>();
|
||||
|
||||
AZ::SimpleLcgRandom rand(AZStd::GetTimeNowMicroSecond());
|
||||
// Create a Box Shape to map our gradient into
|
||||
LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(shapeHalfBounds * 2.0f));
|
||||
auto boxComponent = noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
|
||||
boxComponent->SetConfiguration(boxConfig);
|
||||
|
||||
// Create a Fast Noise component with an adjusted frequency. (The defaults of Perlin noise with frequency=1.0 would cause us
|
||||
// to always get back the same noise value)
|
||||
FastNoiseGem::FastNoiseGradientConfig cfg;
|
||||
|
||||
cfg.m_frequency = 0.01f;
|
||||
noiseEntity->CreateComponent<FastNoiseGem::FastNoiseGradientComponent>(cfg);
|
||||
noiseEntity->CreateComponent<MockGradientTransformComponent>();
|
||||
|
||||
m_application.AddEntity(noiseEntity);
|
||||
noiseEntity->Init();
|
||||
noiseEntity->Activate();
|
||||
|
||||
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
ASSERT_TRUE(noiseComp != nullptr);
|
||||
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
|
||||
// Create a gradient sampler and run through a series of points to see if they match expectations.
|
||||
UnitTest::GradientSignalTestHelpers::CompareGetValueAndGetValues(noiseEntity->GetId(), shapeHalfBounds);
|
||||
}
|
||||
|
||||
#if FASTNOISE_EDITOR
|
||||
#include <EditorFastNoiseGradientComponent.h>
|
||||
|
||||
TEST_F(FastNoiseTestApp, FastNoise_EditorCreateGameEntity)
|
||||
{
|
||||
AZStd::unique_ptr<AZ::Entity> noiseEntity(aznew AZ::Entity("editor_noise_entity"));
|
||||
ASSERT_TRUE(noiseEntity != nullptr);
|
||||
|
||||
FastNoiseGem::EditorFastNoiseGradientComponent editor;
|
||||
auto* editorBase = static_cast<AzToolsFramework::Components::EditorComponentBase*>(&editor);
|
||||
editorBase->BuildGameEntity(noiseEntity.get());
|
||||
|
||||
// the new game entity's ocean component should look like the default one
|
||||
FastNoiseGem::FastNoiseGradientConfig cfg;
|
||||
|
||||
FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent<FastNoiseGem::FastNoiseGradientComponent>();
|
||||
ASSERT_TRUE(noiseComp != nullptr);
|
||||
reinterpret_cast<FastNoiseGradientComponentTester*>(noiseComp)->AssertTrue(cfg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems.
|
||||
AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment);
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzTest/GemTestEnvironment.h>
|
||||
#include <FastNoiseGradientComponent.h>
|
||||
#include <FastNoiseSystemComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// The FastNoise unit tests need to use the GemTestEnvironment to load the GradientSignal and LmbrCentral Gems so that
|
||||
// GradientTransform components can be used in the unit tests and benchmarks.
|
||||
class FastNoiseTestEnvironment
|
||||
: public AZ::Test::GemTestEnvironment
|
||||
{
|
||||
public:
|
||||
void AddGemsAndComponents() override
|
||||
{
|
||||
AddDynamicModulePaths({ "GradientSignal" });
|
||||
AddDynamicModulePaths({ "LmbrCentral" });
|
||||
|
||||
AddComponentDescriptors({
|
||||
AzFramework::TransformComponent::CreateDescriptor(),
|
||||
FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor(),
|
||||
FastNoiseGem::FastNoiseGradientComponent::CreateDescriptor()
|
||||
});
|
||||
|
||||
AddRequiredComponents({ FastNoiseGem::FastNoiseSystemComponent::TYPEINFO_Uuid() });
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
//! The Benchmark environment is used for one time setup and tear down of shared resources
|
||||
class FastNoiseBenchmarkEnvironment
|
||||
: public AZ::Test::BenchmarkEnvironmentBase
|
||||
, public FastNoiseTestEnvironment
|
||||
|
||||
{
|
||||
protected:
|
||||
void SetUpBenchmark() override
|
||||
{
|
||||
SetupEnvironment();
|
||||
}
|
||||
|
||||
void TearDownBenchmark() override
|
||||
{
|
||||
TeardownEnvironment();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/FastNoiseEditorTest.cpp
|
||||
Source/FastNoiseModule.h
|
||||
Source/FastNoiseModule.cpp
|
||||
)
|
||||
@@ -7,6 +7,7 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/FastNoiseBenchmarks.cpp
|
||||
Tests/FastNoiseTest.cpp
|
||||
Source/FastNoiseModule.h
|
||||
Source/FastNoiseModule.cpp
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifdef HAVE_BENCHMARK
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
#include <Tests/GradientSignalTestHelpers.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
@@ -21,220 +22,42 @@ namespace UnitTest
|
||||
class GradientGetValues : public GradientSignalBenchmarkFixture
|
||||
{
|
||||
public:
|
||||
// We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases
|
||||
// to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark
|
||||
// function for each test case for each gradient.
|
||||
enum GetValuePermutation : int64_t
|
||||
{
|
||||
EBUS_GET_VALUE,
|
||||
EBUS_GET_VALUES,
|
||||
SAMPLER_GET_VALUE,
|
||||
SAMPLER_GET_VALUES,
|
||||
};
|
||||
|
||||
// Create an arbitrary size shape for creating our gradients for benchmark runs.
|
||||
const float TestShapeHalfBounds = 128.0f;
|
||||
|
||||
void FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width)
|
||||
{
|
||||
size_t index = 0;
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
positions[index++] = AZ::Vector3(x, y, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
GradientSignal::GradientSampleParams params;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
|
||||
// Call GetValue() on the EBus for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
float value = 0.0f;
|
||||
params.m_position = AZ::Vector3(x, y, 0.0f);
|
||||
GradientSignal::GradientRequestBus::EventResult(
|
||||
value, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
|
||||
benchmark::DoNotOptimize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
float height = aznumeric_cast<float>(queryRange);
|
||||
float width = aznumeric_cast<float>(queryRange);
|
||||
int64_t totalQueryPoints = queryRange * queryRange;
|
||||
|
||||
// Call GetValues() for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
|
||||
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
|
||||
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
|
||||
FillQueryPositions(positions, height, width);
|
||||
|
||||
// Query and get the results.
|
||||
AZStd::vector<float> results(totalQueryPoints);
|
||||
GradientSignal::GradientRequestBus::Event(
|
||||
gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
|
||||
}
|
||||
}
|
||||
|
||||
void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Create a gradient sampler to use for querying our gradient.
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientId;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
|
||||
// Call GetValue() through the GradientSampler for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(x, y, 0.0f);
|
||||
float value = gradientSampler.GetValue(params);
|
||||
benchmark::DoNotOptimize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Create a gradient sampler to use for querying our gradient.
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientId;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
const int64_t totalQueryPoints = queryRange * queryRange;
|
||||
|
||||
// Call GetValues() through the GradientSampler for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
|
||||
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
|
||||
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
|
||||
FillQueryPositions(positions, height, width);
|
||||
|
||||
// Query and get the results.
|
||||
AZStd::vector<float> results(totalQueryPoints);
|
||||
gradientSampler.GetValues(positions, results);
|
||||
}
|
||||
}
|
||||
|
||||
void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId)
|
||||
{
|
||||
switch (state.range(0))
|
||||
{
|
||||
case GetValuePermutation::EBUS_GET_VALUE:
|
||||
RunEBusGetValueBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::EBUS_GET_VALUES:
|
||||
RunEBusGetValuesBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::SAMPLER_GET_VALUE:
|
||||
RunSamplerGetValueBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::SAMPLER_GET_VALUES:
|
||||
RunSamplerGetValuesBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Benchmark permutation type not supported.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by
|
||||
// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results.
|
||||
#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \
|
||||
->ArgNames({ "EbusGetValue", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \
|
||||
->ArgNames({ "EbusGetValues", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \
|
||||
->ArgNames({ "SamplerGetValue", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \
|
||||
->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \
|
||||
->ArgNames({ "SamplerGetValues", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Base Gradients
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state)
|
||||
{
|
||||
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state)
|
||||
{
|
||||
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state)
|
||||
{
|
||||
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state)
|
||||
{
|
||||
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state)
|
||||
{
|
||||
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient);
|
||||
@@ -250,21 +73,21 @@ namespace UnitTest
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state)
|
||||
@@ -272,35 +95,35 @@ namespace UnitTest
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_ThresholdGradient)(benchmark::State& state)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient);
|
||||
@@ -321,7 +144,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state)
|
||||
@@ -330,7 +153,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state)
|
||||
@@ -339,7 +162,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
|
||||
RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
|
||||
}
|
||||
|
||||
GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
#include <Tests/GradientSignalTestHelpers.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
@@ -18,79 +19,36 @@ namespace UnitTest
|
||||
// Create an arbitrary size shape for comparing values within. It should be large enough that we detect any value anomalies
|
||||
// but small enough that the tests run quickly.
|
||||
const float TestShapeHalfBounds = 128.0f;
|
||||
|
||||
void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId)
|
||||
{
|
||||
// Create a gradient sampler and run through a series of points to see if they match expectations.
|
||||
|
||||
const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds));
|
||||
const AZ::Vector2 stepSize(1.0f, 1.0f);
|
||||
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
const size_t numSamplesX = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX()));
|
||||
const size_t numSamplesY = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY()));
|
||||
|
||||
// Build up the list of positions to query.
|
||||
AZStd::vector<AZ::Vector3> positions(numSamplesX * numSamplesY);
|
||||
size_t index = 0;
|
||||
for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++)
|
||||
{
|
||||
float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex);
|
||||
for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++)
|
||||
{
|
||||
float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex);
|
||||
positions[index++] = AZ::Vector3(x, y, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the results from GetValues
|
||||
AZStd::vector<float> results(numSamplesX * numSamplesY);
|
||||
gradientSampler.GetValues(positions, results);
|
||||
|
||||
// For each position, call GetValue and verify that the values match.
|
||||
for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = positions[positionIndex];
|
||||
float value = gradientSampler.GetValue(params);
|
||||
|
||||
// We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no
|
||||
// reason to keep running and printing failures for every value.
|
||||
ASSERT_NEAR(value, results[positionIndex], 0.000001f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, ImageGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto entity = BuildTestImageGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, PerlinGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, RandomGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, ConstantGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, ShapeAreaFalloffGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, DitherGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
@@ -98,21 +56,21 @@ namespace UnitTest
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
|
||||
auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, InvertGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestInvertGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, LevelsGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, MixedGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
@@ -120,35 +78,35 @@ namespace UnitTest
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, PosterizeGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, ReferenceGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, SmoothStepGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, ThresholdGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
{
|
||||
auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
|
||||
auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceAltitudeGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
@@ -157,7 +115,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceMaskGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
@@ -166,7 +124,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalGetValuesTestsFixture, SurfaceSlopeGradientComponent_VerifyGetValueAndGetValuesMatch)
|
||||
@@ -175,7 +133,7 @@ namespace UnitTest
|
||||
CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)));
|
||||
|
||||
auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
|
||||
CompareGetValueAndGetValues(entity->GetId());
|
||||
GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <Tests/GradientSignalTestHelpers.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <GradientSignal/GradientSampler.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
void GradientSignalTestHelpers::CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds)
|
||||
{
|
||||
// Create a gradient sampler and run through a series of points to see if they match expectations.
|
||||
|
||||
const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-shapeHalfBounds), AZ::Vector3(shapeHalfBounds));
|
||||
const AZ::Vector2 stepSize(1.0f, 1.0f);
|
||||
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
const size_t numSamplesX = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX()));
|
||||
const size_t numSamplesY = aznumeric_cast<size_t>(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY()));
|
||||
|
||||
// Build up the list of positions to query.
|
||||
AZStd::vector<AZ::Vector3> positions(numSamplesX * numSamplesY);
|
||||
size_t index = 0;
|
||||
for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++)
|
||||
{
|
||||
float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex);
|
||||
for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++)
|
||||
{
|
||||
float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex);
|
||||
positions[index++] = AZ::Vector3(x, y, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the results from GetValues
|
||||
AZStd::vector<float> results(numSamplesX * numSamplesY);
|
||||
gradientSampler.GetValues(positions, results);
|
||||
|
||||
// For each position, call GetValue and verify that the values match.
|
||||
for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = positions[positionIndex];
|
||||
float value = gradientSampler.GetValue(params);
|
||||
|
||||
// We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no
|
||||
// reason to keep running and printing failures for every value.
|
||||
ASSERT_NEAR(value, results[positionIndex], 0.000001f);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
|
||||
void GradientSignalTestHelpers::FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width)
|
||||
{
|
||||
size_t index = 0;
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
positions[index++] = AZ::Vector3(x, y, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GradientSignalTestHelpers::RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
GradientSignal::GradientSampleParams params;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
|
||||
// Call GetValue() on the EBus for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
float value = 0.0f;
|
||||
params.m_position = AZ::Vector3(x, y, 0.0f);
|
||||
GradientSignal::GradientRequestBus::EventResult(
|
||||
value, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
|
||||
benchmark::DoNotOptimize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GradientSignalTestHelpers::RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
float height = aznumeric_cast<float>(queryRange);
|
||||
float width = aznumeric_cast<float>(queryRange);
|
||||
int64_t totalQueryPoints = queryRange * queryRange;
|
||||
|
||||
// Call GetValues() for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
|
||||
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
|
||||
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
|
||||
FillQueryPositions(positions, height, width);
|
||||
|
||||
// Query and get the results.
|
||||
AZStd::vector<float> results(totalQueryPoints);
|
||||
GradientSignal::GradientRequestBus::Event(
|
||||
gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
|
||||
}
|
||||
}
|
||||
|
||||
void GradientSignalTestHelpers::RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Create a gradient sampler to use for querying our gradient.
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientId;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
|
||||
// Call GetValue() through the GradientSampler for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(x, y, 0.0f);
|
||||
float value = gradientSampler.GetValue(params);
|
||||
benchmark::DoNotOptimize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GradientSignalTestHelpers::RunSamplerGetValuesBenchmark(
|
||||
benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// Create a gradient sampler to use for querying our gradient.
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientId;
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
const float height = aznumeric_cast<float>(queryRange);
|
||||
const float width = aznumeric_cast<float>(queryRange);
|
||||
const int64_t totalQueryPoints = queryRange * queryRange;
|
||||
|
||||
// Call GetValues() through the GradientSampler for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
// Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create
|
||||
// each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable.
|
||||
AZStd::vector<AZ::Vector3> positions(totalQueryPoints);
|
||||
FillQueryPositions(positions, height, width);
|
||||
|
||||
// Query and get the results.
|
||||
AZStd::vector<float> results(totalQueryPoints);
|
||||
gradientSampler.GetValues(positions, results);
|
||||
}
|
||||
}
|
||||
|
||||
void GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId)
|
||||
{
|
||||
switch (state.range(0))
|
||||
{
|
||||
case GetValuePermutation::EBUS_GET_VALUE:
|
||||
RunEBusGetValueBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::EBUS_GET_VALUES:
|
||||
RunEBusGetValuesBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::SAMPLER_GET_VALUE:
|
||||
RunSamplerGetValueBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
case GetValuePermutation::SAMPLER_GET_VALUES:
|
||||
RunSamplerGetValuesBenchmark(state, gradientId, state.range(1));
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Benchmark permutation type not supported.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class GradientSignalTestHelpers
|
||||
{
|
||||
public:
|
||||
static void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds);
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
// We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases
|
||||
// to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark
|
||||
// function for each test case for each gradient.
|
||||
enum GetValuePermutation : int64_t
|
||||
{
|
||||
EBUS_GET_VALUE,
|
||||
EBUS_GET_VALUES,
|
||||
SAMPLER_GET_VALUE,
|
||||
SAMPLER_GET_VALUES,
|
||||
};
|
||||
|
||||
static void FillQueryPositions(AZStd::vector<AZ::Vector3>& positions, float height, float width);
|
||||
|
||||
static void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
|
||||
static void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
|
||||
static void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
|
||||
static void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange);
|
||||
static void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId);
|
||||
|
||||
// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by
|
||||
// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results.
|
||||
#ifndef GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F
|
||||
#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \
|
||||
->ArgNames({ "EbusGetValue", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \
|
||||
->ArgNames({ "EbusGetValues", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \
|
||||
->ArgNames({ "SamplerGetValue", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond); \
|
||||
BENCHMARK_REGISTER_F(Fixture, Func) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \
|
||||
->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \
|
||||
->ArgNames({ "SamplerGetValues", "size" }) \
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -7,6 +7,8 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/GradientSignalTestHelpers.cpp
|
||||
Tests/GradientSignalTestHelpers.h
|
||||
Tests/GradientSignalTestFixtures.cpp
|
||||
Tests/GradientSignalTestFixtures.h
|
||||
Tests/GradientSignalTestMocks.cpp
|
||||
|
||||
Reference in New Issue
Block a user