From ffa9cc3a66e7a6df95b18b19d3542370c6eed307 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Wed, 12 Jan 2022 08:46:10 -0600 Subject: [PATCH] Unit tests and benchmarks for GetValues() (#6823) * Benchmarks and tests for Image and Constant GetValues Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Verify GetValues for Perlin and Random Gradients Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Standardized the assert format for GetValues(). Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * More GetValues unit tests and test cleanup Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed typos Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * GetValues() unit tests for surface gradients. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Benchmarks for ShapeAreaFalloff Gradient Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Added benchmarks for all remaining gradients and cleaned up the helper methods. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Renamed class for better report formatting. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Added missing Mocks dependencies for the Editor tests. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- Gems/GradientSignal/Code/CMakeLists.txt | 3 + .../Ebuses/GradientRequestBus.h | 27 +- .../Include/GradientSignal/GradientSampler.h | 4 +- .../Code/Tests/GradientSignalBenchmarks.cpp | 401 +++++++++---- .../Tests/GradientSignalGetValuesTests.cpp | 182 ++++++ .../Code/Tests/GradientSignalImageTests.cpp | 1 - .../Tests/GradientSignalReferencesTests.cpp | 16 +- .../Tests/GradientSignalServicesTests.cpp | 9 +- .../Code/Tests/GradientSignalTestFixtures.cpp | 562 +++++++++++------- .../Code/Tests/GradientSignalTestFixtures.h | 59 +- .../Code/gradientsignal_tests_files.cmake | 1 + .../Source/Shape/ReferenceShapeComponent.cpp | 16 +- .../TerrainHeightGradientListComponent.cpp | 2 +- .../Components/AreaBlenderComponent.cpp | 10 +- 14 files changed, 907 insertions(+), 386 deletions(-) create mode 100644 Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index 657a88db47..d4cf666630 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -141,6 +141,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTestShared Gem::GradientSignal.Static Gem::LmbrCentral + Gem::LmbrCentral.Mocks Gem::GradientSignal.Mocks ) @@ -160,6 +161,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Gem::GradientSignal.Tests.Static Gem::GradientSignal.Static Gem::LmbrCentral + Gem::LmbrCentral.Mocks Gem::GradientSignal.Mocks ) ly_add_googletest( @@ -190,6 +192,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Gem::GradientSignal.Static Gem::GradientSignal.Editor.Static Gem::LmbrCentral.Editor + Gem::LmbrCentral.Mocks ) ly_add_googletest( NAME Gem::GradientSignal.Editor.Tests diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h index d0fcabf746..3a215c5b5d 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Ebuses/GradientRequestBus.h @@ -62,22 +62,21 @@ namespace GradientSignal // Reference implementation of GetValues for any gradients that don't have their own optimized implementations. // This is 10%-60% faster than calling GetValue via EBus many times due to the per-call EBus overhead. - AZ_Assert( - positions.size() == outValues.size(), "input and output lists are different sizes (%zu vs %zu).", - positions.size(), outValues.size()); - - if (positions.size() == outValues.size()) + if (positions.size() != outValues.size()) { - GradientSampleParams sampleParams; - for (size_t index = 0; index < positions.size(); index++) - { - sampleParams.m_position = positions[index]; + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; + } - // The const_cast is necessary for now since array_view currently only supports const entries. - // If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed. - auto& outValue = const_cast(outValues[index]); - outValue = GetValue(sampleParams); - } + GradientSampleParams sampleParams; + for (size_t index = 0; index < positions.size(); index++) + { + sampleParams.m_position = positions[index]; + + // The const_cast is necessary for now since array_view currently only supports const entries. + // If/when array_view is fixed to support non-const, or AZStd::span gets created, the const_cast can get removed. + auto& outValue = const_cast(outValues[index]); + outValue = GetValue(sampleParams); } } diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h b/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h index 454be938a5..a2e1849590 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/GradientSampler.h @@ -120,7 +120,7 @@ namespace GradientSignal if (m_isRequestInProgress) { - AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependences with gradient entity references"); + AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependencies with gradient entity references"); } else { @@ -197,7 +197,7 @@ namespace GradientSignal if (m_isRequestInProgress) { - AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependences with gradient entity references"); + AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependencies with gradient entity references"); ClearOutputValues(outValues); return; } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp index 6383b627c1..bd4ccf5205 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp @@ -16,162 +16,337 @@ #include #include -#include -#include -#include -#include - namespace UnitTest { - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue)(benchmark::State& state) + class GradientGetValues : public GradientSignalBenchmarkFixture { - CreateTestImageGradient(m_testEntity.get()); - RunEBusGetValueBenchmark(state); - } + 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, + }; - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) + // Create an arbitrary size shape for creating our gradients for benchmark runs. + const float TestShapeHalfBounds = 128.0f; + + void FillQueryPositions(AZStd::vector& 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(queryRange); + const float width = aznumeric_cast(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(queryRange); + float width = aznumeric_cast(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 positions(totalQueryPoints); + FillQueryPositions(positions, height, width); + + // Query and get the results. + AZStd::vector 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(queryRange); + const float width = aznumeric_cast(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(queryRange); + const float width = aznumeric_cast(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 positions(totalQueryPoints); + FillQueryPositions(positions, height, width); + + // Query and get the results. + AZStd::vector 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); - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues)(benchmark::State& state) + // -------------------------------------------------------------------------------------- + // Base Gradients + + BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state) { - CreateTestImageGradient(m_testEntity.get()); - RunEBusGetValuesBenchmark(state); + auto entity = BuildTestConstantGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValue)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state) { - CreateTestImageGradient(m_testEntity.get()); - RunSamplerGetValueBenchmark(state); + auto entity = BuildTestImageGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValues)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state) { - CreateTestImageGradient(m_testEntity.get()); - RunSamplerGetValuesBenchmark(state); + auto entity = BuildTestPerlinGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValue)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state) { - CreateTestPerlinGradient(m_testEntity.get()); - RunEBusGetValueBenchmark(state); + auto entity = BuildTestRandomGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValues)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state) { - CreateTestPerlinGradient(m_testEntity.get()); - RunEBusGetValuesBenchmark(state); + auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ImageGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PerlinGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_RandomGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ShapeAreaFalloffGradient); - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValue)(benchmark::State& state) + // -------------------------------------------------------------------------------------- + // Gradient Modifiers + + BENCHMARK_DEFINE_F(GradientGetValues, BM_DitherGradient)(benchmark::State& state) { - CreateTestPerlinGradient(m_testEntity.get()); - RunSamplerGetValueBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValues)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state) { - CreateTestPerlinGradient(m_testEntity.get()); - RunSamplerGetValuesBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValue)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state) { - CreateTestRandomGradient(m_testEntity.get()); - RunEBusGetValueBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValues)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state) { - CreateTestRandomGradient(m_testEntity.get()); - RunEBusGetValuesBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds); + auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientEBusGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValue)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state) { - CreateTestRandomGradient(m_testEntity.get()); - RunSamplerGetValueBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValue) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); - - BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValues)(benchmark::State& state) + BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state) { - CreateTestRandomGradient(m_testEntity.get()); - RunSamplerGetValuesBenchmark(state); + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId()); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } - BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValues) - ->Args({ 1024, 1024 }) - ->Args({ 2048, 2048 }) - ->Args({ 4096, 4096 }) - ->Unit(::benchmark::kMillisecond); + BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId()); + 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()); + } + + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_InvertGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_LevelsGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_MixedGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PosterizeGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ReferenceGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SmoothStepGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ThresholdGradient); + + // -------------------------------------------------------------------------------------- + // Surface Gradients + + BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceAltitudeGradient)(benchmark::State& state) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + } + + BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + } + + BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds); + RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + } + + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceMaskGradient); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceSlopeGradient); #endif - - - - } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp new file mode 100644 index 0000000000..5504fa5b45 --- /dev/null +++ b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp @@ -0,0 +1,182 @@ +/* + * 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 +#include + +namespace UnitTest +{ + struct GradientSignalGetValuesTestsFixture + : public GradientSignalTest + { + // 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(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY())); + + // Build up the list of positions to query. + AZStd::vector 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 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_EQ instead of EXPECT_EQ 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_EQ(value, results[positionIndex]); + } + } + }; + + TEST_F(GradientSignalGetValuesTestsFixture, ImageGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto entity = BuildTestImageGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, PerlinGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto entity = BuildTestPerlinGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, RandomGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto entity = BuildTestRandomGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, ConstantGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto entity = BuildTestConstantGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, ShapeAreaFalloffGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, DitherGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + + auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, InvertGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestInvertGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, LevelsGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, MixedGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds); + auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, PosterizeGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, ReferenceGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, SmoothStepGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, ThresholdGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); + auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId()); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, SurfaceAltitudeGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, SurfaceMaskGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } + + TEST_F(GradientSignalGetValuesTestsFixture, SurfaceSlopeGradientComponent_VerifyGetValueAndGetValuesMatch) + { + auto mockSurfaceDataSystem = + CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); + + auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds); + CompareGetValueAndGetValues(entity->GetId()); + } +} + + diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp index e99bf1de5b..5cd3c7edf6 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalImageTests.cpp @@ -417,7 +417,6 @@ namespace UnitTest TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); } } - } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp index 32cd483c81..cc91c58fce 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp @@ -371,12 +371,9 @@ namespace UnitTest const AZ::EntityId id = mockReference->GetId(); MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); - GradientSignal::ReferenceGradientConfig config; - config.m_gradientSampler.m_gradientId = mockReference->GetId(); - - auto entity = CreateEntity(); - CreateComponent(entity.get(), config); - ActivateEntity(entity.get()); + // Create a reference gradient with an arbitrary box shape on it. + const float HalfBounds = 64.0f; + auto entity = BuildTestReferenceGradient(HalfBounds, mockReference->GetId()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); } @@ -385,10 +382,9 @@ namespace UnitTest { // Verify that gradient references can validate and disconnect cyclic connections - auto constantGradientEntity = CreateEntity(); - GradientSignal::ConstantGradientConfig constantGradientConfig; - CreateComponent(constantGradientEntity.get(), constantGradientConfig); - ActivateEntity(constantGradientEntity.get()); + // Create a constant gradient with an arbitrary box shape on it. + const float HalfBounds = 64.0f; + auto constantGradientEntity = BuildTestConstantGradient(HalfBounds); // Verify cyclic reference test passes when pointing to gradient generator entity auto referenceGradientEntity1 = CreateEntity(); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp index dd81c14a09..ec770f038d 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalServicesTests.cpp @@ -212,12 +212,9 @@ namespace UnitTest const AZ::EntityId id = entityMock->GetId(); UnitTest::MockGradientArrayRequestsBus mockGradientRequestsBus(id, inputData, dataSize); - GradientSignal::InvertGradientConfig config; - config.m_gradientSampler.m_gradientId = entityMock->GetId(); - - auto entity = CreateEntity(); - CreateComponent(entity.get(), config); - ActivateEntity(entity.get()); + // Create the entity with an arbitrarily-sized box. + const float HalfBounds = 64.0f; + auto entity = BuildTestInvertGradient(HalfBounds, entityMock->GetId()); TestFixedDataSampler(expectedOutput, dataSize, entity->GetId()); } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp index 77568d3321..154e9032b2 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp @@ -9,10 +9,30 @@ #include +#include #include + +// Base gradient components +#include #include #include #include +#include + +// Gradient modifier components +#include +#include +#include +#include +#include +#include +#include +#include + +// Gradient surface data components +#include +#include +#include namespace UnitTest { @@ -32,12 +52,18 @@ namespace UnitTest AZ::Data::AssetManager::Create(desc); m_mockHandler = new ImageAssetMockAssetHandler(); AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid()); + + m_mockShapeHandlers = new AZStd::vector>>(); } void GradientSignalBaseFixture::TearDownCoreSystems() { + // Clear any mock shape handlers that we've created for our test entities. + delete m_mockShapeHandlers; + AZ::Data::AssetManager::Instance().UnregisterHandler(m_mockHandler); delete m_mockHandler; // delete after removing from the asset manager + AzFramework::LegacyAssetEventBus::ClearQueuedEvents(); AZ::Data::AssetManager::Destroy(); AZ::AllocatorInstance::Destroy(); @@ -47,6 +73,338 @@ namespace UnitTest m_systemEntity = nullptr; } + AZStd::unique_ptr> GradientSignalBaseFixture::CreateMockShape( + const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId) + { + AZStd::unique_ptr> mockShape = + AZStd::make_unique>(shapeEntityId); + + ON_CALL(*mockShape, GetEncompassingAabb).WillByDefault(testing::Return(spawnerBox)); + ON_CALL(*mockShape, GetTransformAndLocalBounds) + .WillByDefault( + [spawnerBox](AZ::Transform& transform, AZ::Aabb& bounds) + { + transform = AZ::Transform::CreateTranslation(spawnerBox.GetCenter()); + bounds = spawnerBox.GetTranslated(-spawnerBox.GetCenter()); + }); + ON_CALL(*mockShape, IsPointInside) + .WillByDefault( + [spawnerBox](const AZ::Vector3& point) -> bool + { + return spawnerBox.Contains(point); + }); + + return mockShape; + } + + AZStd::unique_ptr GradientSignalBaseFixture::CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox) + { + SurfaceData::SurfacePoint point; + AZStd::unique_ptr mockSurfaceDataSystem = AZStd::make_unique(); + + // Give the mock surface data a bunch of fake point values to return. + for (float y = spawnerBox.GetMin().GetY(); y < spawnerBox.GetMax().GetY(); y+= 1.0f) + { + for (float x = spawnerBox.GetMin().GetX(); x < spawnerBox.GetMax().GetX(); x += 1.0f) + { + // Use our x distance into the spawnerBox as an arbitrary percentage value that we'll use to calculate + // our other arbitrary values below. + float arbitraryPercentage = AZStd::abs(x / spawnerBox.GetExtents().GetX()); + + // Create a position that's between min and max Z of the box. + point.m_position = AZ::Vector3(x, y, AZ::Lerp(spawnerBox.GetMin().GetZ(), spawnerBox.GetMax().GetZ(), arbitraryPercentage)); + // Create an arbitrary normal value. + point.m_normal = point.m_position.GetNormalized(); + // Create an arbitrary surface value. + point.m_masks[AZ_CRC_CE("test_mask")] = arbitraryPercentage; + + mockSurfaceDataSystem->m_GetSurfacePoints[AZStd::make_pair(x, y)] = { { point } }; + } + } + + return mockSurfaceDataSystem; + } + + AZStd::unique_ptr GradientSignalBaseFixture::CreateTestEntity(float shapeHalfBounds) + { + // Create the base entity + AZStd::unique_ptr testEntity = CreateEntity(); + + // Create a mock Shape component that describes the bounds that we're using to map our gradient into world space. + CreateComponent(testEntity.get()); + + // Create and keep a reference to a mock shape handler that will respond to shape requests for the mock shape. + auto mockShapeHandler = + CreateMockShape(AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds), testEntity->GetId()); + m_mockShapeHandlers->push_back(AZStd::move(mockShapeHandler)); + + // Create a transform that locates our gradient in the center of our desired mock Shape. + auto transform = CreateComponent(testEntity.get()); + transform->SetLocalTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); + transform->SetWorldTM(AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds))); + + return testEntity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestConstantGradient(float shapeHalfBounds) + { + // Create a Constant Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::ConstantGradientConfig config; + config.m_value = 0.75f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestImageGradient(float shapeHalfBounds) + { + // Create an Image Gradient Component with arbitrary sizes and parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::ImageGradientConfig config; + const uint32_t imageSize = 4096; + const int32_t imageSeed = 12345; + config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed); + config.m_tilingX = 1.0f; + config.m_tilingY = 1.0f; + CreateComponent(entity.get(), config); + + // Create a Gradient Transform Component with arbitrary parameters. + GradientSignal::GradientTransformConfig gradientTransformConfig; + gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; + CreateComponent(entity.get(), gradientTransformConfig); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestPerlinGradient(float shapeHalfBounds) + { + // Create a Perlin Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::PerlinGradientConfig config; + config.m_amplitude = 1.0f; + config.m_frequency = 1.1f; + config.m_octave = 4; + config.m_randomSeed = 12345; + CreateComponent(entity.get(), config); + + // Create a Gradient Transform Component with arbitrary parameters. + GradientSignal::GradientTransformConfig gradientTransformConfig; + gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; + CreateComponent(entity.get(), gradientTransformConfig); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestRandomGradient(float shapeHalfBounds) + { + // Create a Random Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::RandomGradientConfig config; + config.m_randomSeed = 12345; + CreateComponent(entity.get(), config); + + // Create a Gradient Transform Component with arbitrary parameters. + GradientSignal::GradientTransformConfig gradientTransformConfig; + gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; + CreateComponent(entity.get(), gradientTransformConfig); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestShapeAreaFalloffGradient(float shapeHalfBounds) + { + // Create a Shape Area Falloff Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::ShapeAreaFalloffGradientConfig config; + config.m_shapeEntityId = entity->GetId(); + config.m_falloffWidth = 16.0f; + config.m_falloffType = GradientSignal::FalloffType::InnerOuter; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestDitherGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Dither Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::DitherGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_useSystemPointsPerUnit = false; + config.m_pointsPerUnit = 1.0f; + config.m_patternOffset = AZ::Vector3::CreateZero(); + config.m_patternType = GradientSignal::DitherGradientConfig::BayerPatternType::PATTERN_SIZE_4x4; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestInvertGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create an Invert Gradient Component. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::InvertGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestLevelsGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Levels Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::LevelsGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_inputMin = 0.1f; + config.m_inputMid = 0.3f; + config.m_inputMax = 0.9f; + config.m_outputMin = 0.0f; + config.m_outputMax = 1.0f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestMixedGradient( + float shapeHalfBounds, const AZ::EntityId& baseGradientId, const AZ::EntityId& mixedGradientId) + { + // Create a Mixed Gradient Component that mixes two input gradients together in arbitrary ways. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::MixedGradientConfig config; + + GradientSignal::MixedGradientLayer layer; + layer.m_enabled = true; + + layer.m_operation = GradientSignal::MixedGradientLayer::MixingOperation::Initialize; + layer.m_gradientSampler.m_gradientId = baseGradientId; + layer.m_gradientSampler.m_opacity = 1.0f; + config.m_layers.push_back(layer); + + layer.m_operation = GradientSignal::MixedGradientLayer::MixingOperation::Overlay; + layer.m_gradientSampler.m_gradientId = mixedGradientId; + layer.m_gradientSampler.m_opacity = 0.75f; + config.m_layers.push_back(layer); + + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestPosterizeGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Posterize Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::PosterizeGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_mode = GradientSignal::PosterizeGradientConfig::ModeType::Ps; + config.m_bands = 5; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestReferenceGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Reference Gradient Component. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::ReferenceGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_gradientSampler.m_ownerEntityId = entity->GetId(); + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestSmoothStepGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Smooth Step Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::SmoothStepGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_smoothStep.m_falloffMidpoint = 0.75f; + config.m_smoothStep.m_falloffRange = 0.125f; + config.m_smoothStep.m_falloffStrength = 0.25f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestThresholdGradient( + float shapeHalfBounds, const AZ::EntityId& inputGradientId) + { + // Create a Threshold Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::ThresholdGradientConfig config; + config.m_gradientSampler.m_gradientId = inputGradientId; + config.m_threshold = 0.75f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestSurfaceAltitudeGradient(float shapeHalfBounds) + { + // Create a Surface Altitude Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::SurfaceAltitudeGradientConfig config; + config.m_altitudeMin = -5.0f; + config.m_altitudeMax = 15.0f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestSurfaceMaskGradient(float shapeHalfBounds) + { + // Create a Surface Mask Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::SurfaceMaskGradientConfig config; + config.m_surfaceTagList.push_back(AZ_CRC_CE("test_mask")); + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + + AZStd::unique_ptr GradientSignalBaseFixture::BuildTestSurfaceSlopeGradient(float shapeHalfBounds) + { + // Create a Surface Slope Gradient Component with arbitrary parameters. + auto entity = CreateTestEntity(shapeHalfBounds); + GradientSignal::SurfaceSlopeGradientConfig config; + config.m_slopeMin = 5.0f; + config.m_slopeMax = 50.0f; + config.m_rampType = GradientSignal::SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP; + config.m_smoothStep.m_falloffMidpoint = 0.75f; + config.m_smoothStep.m_falloffRange = 0.125f; + config.m_smoothStep.m_falloffStrength = 0.25f; + CreateComponent(entity.get(), config); + + ActivateEntity(entity.get()); + return entity; + } + void GradientSignalTest::TestFixedDataSampler(const AZStd::vector& expectedOutput, int size, AZ::EntityId gradientEntityId) { GradientSignal::GradientSampler gradientSampler; @@ -67,209 +425,5 @@ namespace UnitTest } } } - -#ifdef HAVE_BENCHMARK - void GradientSignalBenchmarkFixture::CreateTestEntity(float shapeHalfBounds) - { - // Create the base entity - m_testEntity = CreateEntity(); - - // Create a mock Shape component that describes the bounds that we're using to map our gradient into world space. - CreateComponent(m_testEntity.get()); - MockShapeComponentHandler mockShapeHandler(m_testEntity->GetId()); - mockShapeHandler.m_GetLocalBounds = AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds); - - // Create a mock Transform component that locates our gradient in the center of our desired mock Shape. - MockTransformHandler mockTransformHandler; - mockTransformHandler.m_GetLocalTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)); - mockTransformHandler.m_GetWorldTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds)); - mockTransformHandler.BusConnect(m_testEntity->GetId()); - } - - void GradientSignalBenchmarkFixture::DestroyTestEntity() - { - m_testEntity.reset(); - } - - void GradientSignalBenchmarkFixture::CreateTestImageGradient(AZ::Entity* entity) - { - // Create the Image Gradient Component with some default sizes and parameters. - GradientSignal::ImageGradientConfig config; - const uint32_t imageSize = 4096; - const int32_t imageSeed = 12345; - config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed); - config.m_tilingX = 1.0f; - config.m_tilingY = 1.0f; - CreateComponent(entity, config); - - // Create the Gradient Transform Component with some default parameters. - GradientSignal::GradientTransformConfig gradientTransformConfig; - gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity, gradientTransformConfig); - } - - void GradientSignalBenchmarkFixture::CreateTestPerlinGradient(AZ::Entity* entity) - { - // Create the Perlin Gradient Component with some default sizes and parameters. - GradientSignal::PerlinGradientConfig config; - config.m_amplitude = 1.0f; - config.m_frequency = 1.1f; - config.m_octave = 4; - config.m_randomSeed = 12345; - CreateComponent(entity, config); - - // Create the Gradient Transform Component with some default parameters. - GradientSignal::GradientTransformConfig gradientTransformConfig; - gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity, gradientTransformConfig); - } - - void GradientSignalBenchmarkFixture::CreateTestRandomGradient(AZ::Entity* entity) - { - // Create the Random Gradient Component with some default parameters. - GradientSignal::RandomGradientConfig config; - config.m_randomSeed = 12345; - CreateComponent(entity, config); - - // Create the Gradient Transform Component with some default parameters. - GradientSignal::GradientTransformConfig gradientTransformConfig; - gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None; - CreateComponent(entity, gradientTransformConfig); - } - - void GradientSignalBenchmarkFixture::RunSamplerGetValueBenchmark(benchmark::State& state) - { - AZ_PROFILE_FUNCTION(Entity); - - // All components are created, so activate the entity - ActivateEntity(m_testEntity.get()); - - // Create a gradient sampler and run through a series of points to see if they match expectations. - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = m_testEntity->GetId(); - - // Get the height and width ranges for querying from our benchmark parameters - float height = aznumeric_cast(state.range(0)); - float width = aznumeric_cast(state.range(1)); - - // Call GetValue() 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 GradientSignalBenchmarkFixture::RunSamplerGetValuesBenchmark(benchmark::State& state) - { - AZ_PROFILE_FUNCTION(Entity); - - // All components are created, so activate the entity - ActivateEntity(m_testEntity.get()); - - // Create a gradient sampler and run through a series of points to see if they match expectations. - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = m_testEntity->GetId(); - - // Get the height and width ranges for querying from our benchmark parameters - float height = aznumeric_cast(state.range(0)); - float width = aznumeric_cast(state.range(1)); - int64_t totalQueryPoints = state.range(0) * state.range(1); - - // Call GetValues() for every height and width in our ranges. - for (auto _ : state) - { - // Set up our vector of query positions. - AZStd::vector positions(totalQueryPoints); - 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); - } - } - - // Query and get the results. - AZStd::vector results(totalQueryPoints); - gradientSampler.GetValues(positions, results); - } - } - - void GradientSignalBenchmarkFixture::RunEBusGetValueBenchmark(benchmark::State& state) - { - AZ_PROFILE_FUNCTION(Entity); - - // All components are created, so activate the entity - ActivateEntity(m_testEntity.get()); - - GradientSignal::GradientSampleParams params; - - // Get the height and width ranges for querying from our benchmark parameters - float height = aznumeric_cast(state.range(0)); - float width = aznumeric_cast(state.range(1)); - - // Call GetValue() 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, m_testEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params); - benchmark::DoNotOptimize(value); - } - } - } - } - - void GradientSignalBenchmarkFixture::RunEBusGetValuesBenchmark(benchmark::State& state) - { - AZ_PROFILE_FUNCTION(Entity); - - // All components are created, so activate the entity - ActivateEntity(m_testEntity.get()); - - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = m_testEntity->GetId(); - - // Get the height and width ranges for querying from our benchmark parameters - float height = aznumeric_cast(state.range(0)); - float width = aznumeric_cast(state.range(1)); - int64_t totalQueryPoints = state.range(0) * state.range(1); - - // Call GetValues() for every height and width in our ranges. - for (auto _ : state) - { - // Set up our vector of query positions. - AZStd::vector positions(totalQueryPoints); - 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); - } - } - - // Query and get the results. - AZStd::vector results(totalQueryPoints); - GradientSignal::GradientRequestBus::Event( - m_testEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValues, positions, results); - } - } -#endif - } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h index 13ff69c82d..478f1c1d92 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace UnitTest { @@ -30,22 +31,56 @@ namespace UnitTest } template - AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config) + Component* CreateComponent(AZ::Entity* entity, const Configuration& config) { m_app->RegisterComponentDescriptor(Component::CreateDescriptor()); return entity->CreateComponent(config); } template - AZ::Component* CreateComponent(AZ::Entity* entity) + Component* CreateComponent(AZ::Entity* entity) { m_app->RegisterComponentDescriptor(Component::CreateDescriptor()); return entity->CreateComponent(); } + // Create a mock shape that will respond to the shape bus with proper responses for the given input box. + AZStd::unique_ptr> CreateMockShape( + const AZ::Aabb& spawnerBox, const AZ::EntityId& shapeEntityId); + + // Create a mock SurfaceDataSystem that will respond to requests for surface points with mock responses for points inside + // the given input box. + AZStd::unique_ptr CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox); + + // Create an entity with a mock shape and a transform. It won't be activated yet though, because we expect a gradient component + // to also get added to it first before activation. + AZStd::unique_ptr CreateTestEntity(float shapeHalfBounds); + + // Create and activate an entity with a gradient component of the requested type, initialized with test data. + AZStd::unique_ptr BuildTestConstantGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestImageGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestPerlinGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestRandomGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestShapeAreaFalloffGradient(float shapeHalfBounds); + + AZStd::unique_ptr BuildTestDitherGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestInvertGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestLevelsGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestMixedGradient( + float shapeHalfBounds, const AZ::EntityId& baseGradientId, const AZ::EntityId& mixedGradientId); + AZStd::unique_ptr BuildTestPosterizeGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestReferenceGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestSmoothStepGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + AZStd::unique_ptr BuildTestThresholdGradient(float shapeHalfBounds, const AZ::EntityId& inputGradientId); + + AZStd::unique_ptr BuildTestSurfaceAltitudeGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestSurfaceMaskGradient(float shapeHalfBounds); + AZStd::unique_ptr BuildTestSurfaceSlopeGradient(float shapeHalfBounds); + AZStd::unique_ptr m_app; AZ::Entity* m_systemEntity = nullptr; ImageAssetMockAssetHandler* m_mockHandler = nullptr; + AZStd::vector>>* m_mockShapeHandlers = nullptr; }; struct GradientSignalTest @@ -80,33 +115,15 @@ namespace UnitTest AZ::Debug::TraceMessageBus::Handler::BusConnect(); UnitTest::AllocatorsBenchmarkFixture::SetUp(state); SetupCoreSystems(); - - // Create a default test entity with bounds of 256 m x 256 m x 256 m. - const float shapeHalfBounds = 128.0f; - CreateTestEntity(shapeHalfBounds); } void internalTearDown(const benchmark::State& state) { - DestroyTestEntity(); TearDownCoreSystems(); UnitTest::AllocatorsBenchmarkFixture::TearDown(state); AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); } - void CreateTestEntity(float shapeHalfBounds); - void DestroyTestEntity(); - - void CreateTestImageGradient(AZ::Entity* entity); - void CreateTestPerlinGradient(AZ::Entity* entity); - void CreateTestRandomGradient(AZ::Entity* entity); - - void RunSamplerGetValueBenchmark(benchmark::State& state); - void RunSamplerGetValuesBenchmark(benchmark::State& state); - - void RunEBusGetValueBenchmark(benchmark::State& state); - void RunEBusGetValuesBenchmark(benchmark::State& state); - protected: void SetUp(const benchmark::State& state) override { @@ -125,8 +142,6 @@ namespace UnitTest { internalTearDown(state); } - - AZStd::unique_ptr m_testEntity; }; #endif } diff --git a/Gems/GradientSignal/Code/gradientsignal_tests_files.cmake b/Gems/GradientSignal/Code/gradientsignal_tests_files.cmake index eb799811b7..814347c395 100644 --- a/Gems/GradientSignal/Code/gradientsignal_tests_files.cmake +++ b/Gems/GradientSignal/Code/gradientsignal_tests_files.cmake @@ -8,6 +8,7 @@ set(FILES Tests/GradientSignalBenchmarks.cpp + Tests/GradientSignalGetValuesTests.cpp Tests/GradientSignalImageTests.cpp Tests/GradientSignalReferencesTests.cpp Tests/GradientSignalServicesTests.cpp diff --git a/Gems/LmbrCentral/Code/Source/Shape/ReferenceShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/ReferenceShapeComponent.cpp index 7ed79fe3a3..1fc4bb5107 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/ReferenceShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/ReferenceShapeComponent.cpp @@ -190,7 +190,7 @@ namespace LmbrCentral { AZ::Crc32 result = {}; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -205,7 +205,7 @@ namespace LmbrCentral { AZ::Aabb result = AZ::Aabb::CreateNull(); - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -221,7 +221,7 @@ namespace LmbrCentral transform = AZ::Transform::CreateIdentity(); bounds = AZ::Aabb::CreateNull(); - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -234,7 +234,7 @@ namespace LmbrCentral { bool result = false; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -249,7 +249,7 @@ namespace LmbrCentral { float result = FLT_MAX; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -264,7 +264,7 @@ namespace LmbrCentral { float result = FLT_MAX; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -279,7 +279,7 @@ namespace LmbrCentral { AZ::Vector3 result = AZ::Vector3::CreateZero(); - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; @@ -294,7 +294,7 @@ namespace LmbrCentral { bool result = false; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Shape", !m_isRequestInProgress, "Detected cyclic dependencies with shape entity references"); if (AllowRequest()) { m_isRequestInProgress = true; diff --git a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp index 108ae70632..b9055375d4 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp @@ -160,7 +160,7 @@ namespace Terrain { float maxSample = 0.0f; terrainExists = false; - AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependences with terrain height entity references"); + AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependencies with terrain height entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true; diff --git a/Gems/Vegetation/Code/Source/Components/AreaBlenderComponent.cpp b/Gems/Vegetation/Code/Source/Components/AreaBlenderComponent.cpp index 8bf48de58e..2025ed059f 100644 --- a/Gems/Vegetation/Code/Source/Components/AreaBlenderComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/AreaBlenderComponent.cpp @@ -224,7 +224,7 @@ namespace Vegetation bool result = true; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true; @@ -264,7 +264,7 @@ namespace Vegetation return; } - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true; @@ -295,7 +295,7 @@ namespace Vegetation { AZ_PROFILE_FUNCTION(Entity); - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true; @@ -320,7 +320,7 @@ namespace Vegetation LmbrCentral::ShapeComponentRequestsBus::EventResult(bounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); } - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true; @@ -344,7 +344,7 @@ namespace Vegetation AZ::u32 count = 0; - AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependences with vegetation entity references"); + AZ_WarningOnce("Vegetation", !m_isRequestInProgress, "Detected cyclic dependencies with vegetation entity references"); if (!m_isRequestInProgress) { m_isRequestInProgress = true;