Naive GetValues() implementation. (#6741)
* Naive GetValues() implementation. Added the method itself, and the benchmarks which show that even the naive version is currently 10-50% faster than calling GetValue() for multiple values. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Added comments documenting why the const_cast is there. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed link errors by creating new Shared.Tests lib. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Addressed PR feedback. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed incorrect comparison. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
@@ -124,6 +124,26 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
Mocks
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME GradientSignal.Tests.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
gradientsignal_shared_tests_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
Tests
|
||||
PRIVATE
|
||||
.
|
||||
Source
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::GradientSignal.Static
|
||||
Gem::LmbrCentral
|
||||
Gem::GradientSignal.Mocks
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME GradientSignal.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
@@ -137,6 +157,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::GradientSignal.Tests.Static
|
||||
Gem::GradientSignal.Static
|
||||
Gem::LmbrCentral
|
||||
Gem::GradientSignal.Mocks
|
||||
@@ -165,6 +186,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::GradientSignal.Tests.Static
|
||||
Gem::GradientSignal.Static
|
||||
Gem::GradientSignal.Editor.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
#include <AtomCore/std/containers/array_view.h>
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
struct GradientSampleParams final
|
||||
@@ -49,6 +51,36 @@ namespace GradientSignal
|
||||
*/
|
||||
virtual float GetValue(const GradientSampleParams& sampleParams) const = 0;
|
||||
|
||||
/**
|
||||
* Given a list of positions, generate values. Implementations of this need to be thread-safe without using locks,
|
||||
* as it can get called from multiple threads simultaneously and has the potential to cause lock inversion deadlocks.
|
||||
* \param positions The input list of positions to query.
|
||||
* \param outValues The output list of values. This list is expected to be the same size as the positions list.
|
||||
*/
|
||||
virtual void GetValues(AZStd::array_view<AZ::Vector3> positions, AZStd::array_view<float> outValues) const
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
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<float&>(outValues[index]);
|
||||
outValue = GetValue(sampleParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to check the hierarchy to see if a given entityId exists in the gradient signal chain
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace GradientSignal
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
inline float GetValue(const GradientSampleParams& sampleParams) const;
|
||||
inline void GetValues(AZStd::array_view<AZ::Vector3> positions, AZStd::array_view<float> outValues) const;
|
||||
|
||||
bool IsEntityInHierarchy(const AZ::EntityId& entityId) const;
|
||||
|
||||
@@ -145,4 +146,93 @@ namespace GradientSignal
|
||||
|
||||
return output * m_opacity;
|
||||
}
|
||||
|
||||
inline void GradientSampler::GetValues(AZStd::array_view<AZ::Vector3> positions, AZStd::array_view<float> outValues) const
|
||||
{
|
||||
auto ClearOutputValues = [](AZStd::array_view<float> outValues)
|
||||
{
|
||||
// If we don't have a valid gradient (or it is fully transparent), clear out all the output values.
|
||||
for (size_t index = 0; index < outValues.size(); 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<float&>(outValues[index]);
|
||||
outValue = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
if (m_opacity <= 0.0f || !m_gradientId.IsValid())
|
||||
{
|
||||
ClearOutputValues(outValues);
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Vector3> transformedPositions;
|
||||
bool useTransformedPositions = false;
|
||||
|
||||
// apply transform if set
|
||||
if (m_enableTransform && GradientSamplerUtil::AreTransformParamsSet(*this))
|
||||
{
|
||||
AZ::Matrix3x4 matrix3x4;
|
||||
matrix3x4.SetFromEulerDegrees(m_rotate);
|
||||
matrix3x4.MultiplyByScale(m_scale);
|
||||
matrix3x4.SetTranslation(m_translate);
|
||||
|
||||
useTransformedPositions = true;
|
||||
transformedPositions.resize(positions.size());
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
transformedPositions[index] = matrix3x4 * positions[index];
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Block other threads from accessing the surface data bus while we are in GetValue (which may call into the SurfaceData bus).
|
||||
// We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions
|
||||
// that create false detection of cyclic dependencies when multiple requests occur on different threads simultaneously.
|
||||
// (One case where this was previously able to occur was in rapid updating of the Preview widget on the
|
||||
// GradientSurfaceDataComponent in the Editor when moving the threshold sliders back and forth rapidly)
|
||||
auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false);
|
||||
typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex);
|
||||
|
||||
if (m_isRequestInProgress)
|
||||
{
|
||||
AZ_ErrorOnce("GradientSignal", !m_isRequestInProgress, "Detected cyclic dependences with gradient entity references");
|
||||
ClearOutputValues(outValues);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isRequestInProgress = true;
|
||||
|
||||
GradientRequestBus::Event(
|
||||
m_gradientId, &GradientRequestBus::Events::GetValues, useTransformedPositions ? transformedPositions : positions,
|
||||
outValues);
|
||||
|
||||
m_isRequestInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform any post-fetch transformations on the gradient values (invert, levels, opacity).
|
||||
for (size_t index = 0; index < outValues.size(); 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<float&>(outValues[index]);
|
||||
|
||||
if (m_invertInput)
|
||||
{
|
||||
outValue = 1.0f - outValue;
|
||||
}
|
||||
|
||||
// apply levels if set
|
||||
if (m_enableLevels && GradientSamplerUtil::AreLevelParamsSet(*this))
|
||||
{
|
||||
outValue = GetLevels(outValue, m_inputMid, m_inputMin, m_inputMax, m_outputMin, m_outputMax);
|
||||
}
|
||||
|
||||
outValue = outValue * m_opacity;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,74 +23,145 @@
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)(benchmark::State& state)
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue)(benchmark::State& state)
|
||||
{
|
||||
// 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<GradientSignal::ImageGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
CreateTestImageGradient(m_testEntity.get());
|
||||
RunEBusGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)(benchmark::State& state)
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues)(benchmark::State& state)
|
||||
{
|
||||
// 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<GradientSignal::PerlinGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
CreateTestImageGradient(m_testEntity.get());
|
||||
RunEBusGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientEBusGetValues)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)(benchmark::State& state)
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientSamplerGetValue)(benchmark::State& state)
|
||||
{
|
||||
// Create the Random Gradient Component with some default parameters.
|
||||
GradientSignal::RandomGradientConfig config;
|
||||
config.m_randomSeed = 12345;
|
||||
CreateComponent<GradientSignal::RandomGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
CreateTestImageGradient(m_testEntity.get());
|
||||
RunSamplerGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)
|
||||
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)
|
||||
{
|
||||
CreateTestImageGradient(m_testEntity.get());
|
||||
RunSamplerGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestPerlinGradient(m_testEntity.get());
|
||||
RunEBusGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestPerlinGradient(m_testEntity.get());
|
||||
RunEBusGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientEBusGetValues)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientSamplerGetValue)(benchmark::State& state)
|
||||
{
|
||||
CreateTestPerlinGradient(m_testEntity.get());
|
||||
RunSamplerGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestPerlinGradient(m_testEntity.get());
|
||||
RunSamplerGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestRandomGradient(m_testEntity.get());
|
||||
RunEBusGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestRandomGradient(m_testEntity.get());
|
||||
RunEBusGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestRandomGradient(m_testEntity.get());
|
||||
RunSamplerGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CreateTestRandomGradient(m_testEntity.get());
|
||||
RunSamplerGetValuesBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientSamplerGetValues)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <GradientSignal/Components/GradientTransformComponent.h>
|
||||
#include <GradientSignal/Components/ImageGradientComponent.h>
|
||||
#include <GradientSignal/Components/PerlinGradientComponent.h>
|
||||
#include <GradientSignal/Components/RandomGradientComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
void GradientSignalBaseFixture::SetupCoreSystems()
|
||||
@@ -86,8 +91,56 @@ namespace UnitTest
|
||||
m_testEntity.reset();
|
||||
}
|
||||
|
||||
void GradientSignalBenchmarkFixture::RunGetValueBenchmark(benchmark::State& state)
|
||||
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<GradientSignal::ImageGradientComponent>(entity, config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(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<GradientSignal::PerlinGradientComponent>(entity, config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(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<GradientSignal::RandomGradientComponent>(entity, config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(entity, gradientTransformConfig);
|
||||
}
|
||||
|
||||
void GradientSignalBenchmarkFixture::RunSamplerGetValueBenchmark(benchmark::State& state)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
// All components are created, so activate the entity
|
||||
ActivateEntity(m_testEntity.get());
|
||||
|
||||
@@ -115,6 +168,107 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
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<float>(state.range(0));
|
||||
float width = aznumeric_cast<float>(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<AZ::Vector3> 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<float> 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<float>(state.range(0));
|
||||
float width = aznumeric_cast<float>(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<float>(state.range(0));
|
||||
float width = aznumeric_cast<float>(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<AZ::Vector3> 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<float> results(totalQueryPoints);
|
||||
GradientSignal::GradientRequestBus::Event(
|
||||
m_testEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValues, positions, results);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -97,7 +97,15 @@ namespace UnitTest
|
||||
void CreateTestEntity(float shapeHalfBounds);
|
||||
void DestroyTestEntity();
|
||||
|
||||
void RunGetValueBenchmark(benchmark::State& state);
|
||||
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
|
||||
|
||||
@@ -13,13 +13,14 @@ namespace UnitTest
|
||||
{
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> ImageAssetMockAssetHandler::CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed)
|
||||
{
|
||||
GradientSignal::ImageAsset* imageData =
|
||||
aznew GradientSignal::ImageAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetData::AssetStatus::Ready);
|
||||
imageData->m_imageWidth = width;
|
||||
imageData->m_imageHeight = height;
|
||||
imageData->m_bytesPerPixel = 1;
|
||||
imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageData->m_imageData.reserve(width * height);
|
||||
auto imageAsset = AZ::Data::AssetManager::Instance().CreateAsset<GradientSignal::ImageAsset>(
|
||||
AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
imageAsset->m_imageWidth = width;
|
||||
imageAsset->m_imageHeight = height;
|
||||
imageAsset->m_bytesPerPixel = 1;
|
||||
imageAsset->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageAsset->m_imageData.reserve(width * height);
|
||||
|
||||
size_t value = 0;
|
||||
AZStd::hash_combine(value, seed);
|
||||
@@ -30,23 +31,24 @@ namespace UnitTest
|
||||
{
|
||||
AZStd::hash_combine(value, x);
|
||||
AZStd::hash_combine(value, y);
|
||||
imageData->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
imageAsset->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
return imageAsset;
|
||||
}
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(
|
||||
AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY)
|
||||
{
|
||||
GradientSignal::ImageAsset* imageData =
|
||||
aznew GradientSignal::ImageAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetData::AssetStatus::Ready);
|
||||
imageData->m_imageWidth = width;
|
||||
imageData->m_imageHeight = height;
|
||||
imageData->m_bytesPerPixel = 1;
|
||||
imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageData->m_imageData.reserve(width * height);
|
||||
auto imageAsset = AZ::Data::AssetManager::Instance().CreateAsset<GradientSignal::ImageAsset>(
|
||||
AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
imageAsset->m_imageWidth = width;
|
||||
imageAsset->m_imageHeight = height;
|
||||
imageAsset->m_bytesPerPixel = 1;
|
||||
imageAsset->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageAsset->m_imageData.reserve(width * height);
|
||||
|
||||
const AZ::u8 pixelValue = 255;
|
||||
|
||||
@@ -57,16 +59,16 @@ namespace UnitTest
|
||||
{
|
||||
if ((x == static_cast<int>(pixelX)) && (y == static_cast<int>(pixelY)))
|
||||
{
|
||||
imageData->m_imageData.push_back(pixelValue);
|
||||
imageAsset->m_imageData.push_back(pixelValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageData->m_imageData.push_back(0);
|
||||
imageAsset->m_imageData.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
return imageAsset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ namespace UnitTest
|
||||
static AZ::Data::Asset<GradientSignal::ImageAsset> CreateSpecificPixelImageAsset(
|
||||
AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY);
|
||||
|
||||
AZ::Data::AssetPtr CreateAsset(
|
||||
[[maybe_unused]] const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
return AZ::Data::AssetPtr();
|
||||
// For our mock handler, always mark our assets as immediately ready.
|
||||
return aznew GradientSignal::ImageAsset(id, AZ::Data::AssetData::AssetStatus::Ready);
|
||||
}
|
||||
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
|
||||
@@ -7,6 +7,5 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/GradientSignalTestFixtures.cpp
|
||||
Tests/EditorGradientSignalPreviewTests.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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/GradientSignalTestFixtures.cpp
|
||||
Tests/GradientSignalTestFixtures.h
|
||||
Tests/GradientSignalTestMocks.cpp
|
||||
Tests/GradientSignalTestMocks.h
|
||||
)
|
||||
@@ -13,10 +13,6 @@ set(FILES
|
||||
Tests/GradientSignalServicesTests.cpp
|
||||
Tests/GradientSignalSurfaceTests.cpp
|
||||
Tests/GradientSignalTransformTests.cpp
|
||||
Tests/GradientSignalTestFixtures.cpp
|
||||
Tests/GradientSignalTestFixtures.h
|
||||
Tests/GradientSignalTestMocks.cpp
|
||||
Tests/GradientSignalTestMocks.h
|
||||
Tests/GradientSignalTest.cpp
|
||||
Tests/ImageAssetTests.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user