Add benchmarks to GradientSignal. (#6616)
* Add benchmarks to GradientSignal. Cleaned up and rearranged a bit of the unit testing code to make it reusable from a benchmark suite as well. Added set of benchmarks for measuring GetValue(), so that we can compare against GetValues() when it gets added. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed Editor unit tests. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
@@ -145,6 +145,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
NAME Gem::GradientSignal.Tests
|
||||
)
|
||||
|
||||
ly_add_googlebenchmark(
|
||||
NAME Gem::GradientSignal.Benchmarks
|
||||
TARGET Gem::GradientSignal.Tests
|
||||
)
|
||||
|
||||
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
ly_add_target(
|
||||
NAME GradientSignal.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
|
||||
@@ -35,6 +35,13 @@ namespace GradientSignal
|
||||
static bool VersionConverter(AZ::SerializeContext& context,
|
||||
AZ::SerializeContext::DataElementNode& classElement);
|
||||
|
||||
ImageAsset() = default;
|
||||
|
||||
ImageAsset(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status)
|
||||
: AssetData(assetId, status)
|
||||
{
|
||||
}
|
||||
|
||||
AZ::u32 m_imageWidth = 0;
|
||||
AZ::u32 m_imageHeight = 0;
|
||||
AZ::u8 m_bytesPerPixel = 0;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
#include <GradientSignal/Editor/EditorGradientPreviewRenderer.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
@@ -28,7 +28,6 @@ namespace UnitTest
|
||||
void SetUp() override
|
||||
{
|
||||
GradientSignalTest::SetUp();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
// Set up job manager with two threads so that we can run and test the preview job logic.
|
||||
AZ::JobManagerDesc desc;
|
||||
@@ -46,7 +45,6 @@ namespace UnitTest
|
||||
delete m_jobContext;
|
||||
delete m_jobManager;
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
GradientSignalTest::TearDown();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
|
||||
#include <Source/Components/ImageGradientComponent.h>
|
||||
#include <Source/Components/PerlinGradientComponent.h>
|
||||
#include <Source/Components/RandomGradientComponent.h>
|
||||
#include <Source/Components/GradientTransformComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)(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);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)(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);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)(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);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
@@ -23,69 +23,6 @@ namespace UnitTest
|
||||
struct GradientSignalImageTestsFixture
|
||||
: public GradientSignalTest
|
||||
{
|
||||
struct MockAssetHandler
|
||||
: public AZ::Data::AssetHandler
|
||||
{
|
||||
AZ::Data::AssetPtr CreateAsset([[maybe_unused]] const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
return AZ::Data::AssetPtr();
|
||||
}
|
||||
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GetHandledAssetTypes([[maybe_unused]] AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) override
|
||||
{
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
MockAssetHandler* m_mockHandler = nullptr;
|
||||
GradientSignal::ImageAsset* m_imageData = nullptr;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
GradientSignalTest::SetUp();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
AZ::Data::AssetManager::Descriptor desc;
|
||||
AZ::Data::AssetManager::Create(desc);
|
||||
m_mockHandler = new MockAssetHandler();
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid<GradientSignal::ImageAsset>());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
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<AZ::ThreadPoolAllocator>::Destroy();
|
||||
GradientSignalTest::TearDown();
|
||||
}
|
||||
|
||||
struct AssignIdToAsset
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
void MakeReady()
|
||||
{
|
||||
m_assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom());
|
||||
m_status.store(AZ::Data::AssetData::AssetStatus::Ready);
|
||||
}
|
||||
};
|
||||
|
||||
struct PixelTestSetup
|
||||
{
|
||||
// How to create the source image
|
||||
@@ -105,61 +42,6 @@ namespace UnitTest
|
||||
static const AZ::Vector2 EndOfList;
|
||||
};
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed)
|
||||
{
|
||||
m_imageData = aznew GradientSignal::ImageAsset();
|
||||
m_imageData->m_imageWidth = width;
|
||||
m_imageData->m_imageHeight = height;
|
||||
m_imageData->m_bytesPerPixel = 1;
|
||||
m_imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
|
||||
size_t value = 0;
|
||||
AZStd::hash_combine(value, seed);
|
||||
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
for (AZ::u32 y = 0; y < height; ++y)
|
||||
{
|
||||
AZStd::hash_combine(value, x);
|
||||
AZStd::hash_combine(value, y);
|
||||
m_imageData->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
}
|
||||
}
|
||||
|
||||
reinterpret_cast<AssignIdToAsset*>(m_imageData)->MakeReady();
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(m_imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> CreateSpecificPixelImageAsset(AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY)
|
||||
{
|
||||
m_imageData = aznew GradientSignal::ImageAsset();
|
||||
m_imageData->m_imageWidth = width;
|
||||
m_imageData->m_imageHeight = height;
|
||||
m_imageData->m_bytesPerPixel = 1;
|
||||
m_imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
|
||||
const AZ::u8 pixelValue = 255;
|
||||
|
||||
// Image data should be stored inverted on the y axis relative to our engine, so loop backwards through y.
|
||||
for (int y = static_cast<int>(height) - 1; y >= 0; --y)
|
||||
{
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
if ((x == static_cast<int>(pixelX)) && (y == static_cast<int>(pixelY)))
|
||||
{
|
||||
m_imageData->m_imageData.push_back(pixelValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_imageData->m_imageData.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reinterpret_cast<AssignIdToAsset*>(m_imageData)->MakeReady();
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(m_imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
void TestPixels(GradientSignal::GradientSampler& sampler, AZ::u32 width, AZ::u32 height, float stepSize, const AZStd::vector<AZ::Vector3>& expectedPoints)
|
||||
{
|
||||
AZStd::vector<AZ::Vector3> foundPoints;
|
||||
@@ -203,7 +85,8 @@ namespace UnitTest
|
||||
|
||||
// Create the Image Gradient Component.
|
||||
GradientSignal::ImageGradientConfig config;
|
||||
config.m_imageAsset = CreateSpecificPixelImageAsset(test.m_imageSize, test.m_imageSize, static_cast<AZ::u32>(test.m_pixel.GetX()), static_cast<AZ::u32>(test.m_pixel.GetY()));
|
||||
config.m_imageAsset = ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(
|
||||
test.m_imageSize, test.m_imageSize, static_cast<AZ::u32>(test.m_pixel.GetX()), static_cast<AZ::u32>(test.m_pixel.GetY()));
|
||||
config.m_tilingX = test.m_tiling;
|
||||
config.m_tilingY = test.m_tiling;
|
||||
CreateComponent<GradientSignal::ImageGradientComponent>(entity.get(), config);
|
||||
@@ -495,7 +378,7 @@ namespace UnitTest
|
||||
|
||||
// Create an ImageGradient with a 3x3 asset with the center pixel set.
|
||||
GradientSignal::ImageGradientConfig gradientConfig;
|
||||
gradientConfig.m_imageAsset = CreateSpecificPixelImageAsset(3, 3, 1, 1);
|
||||
gradientConfig.m_imageAsset = ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(3, 3, 1, 1);
|
||||
CreateComponent<GradientSignal::ImageGradientComponent>(entity.get(), gradientConfig);
|
||||
|
||||
// Create the test GradientTransform
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <Source/Components/MixedGradientComponent.h>
|
||||
#include <Source/Components/ReferenceGradientComponent.h>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <Source/Components/ConstantGradientComponent.h>
|
||||
#include <Source/Components/GradientSurfaceDataComponent.h>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <GradientSignal/PerlinImprovedNoise.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
void GradientSignalBaseFixture::SetupCoreSystems()
|
||||
{
|
||||
m_app = AZStd::make_unique<AZ::ComponentApplication>();
|
||||
ASSERT_TRUE(m_app != nullptr);
|
||||
|
||||
AZ::ComponentApplication::Descriptor componentAppDesc;
|
||||
|
||||
m_systemEntity = m_app->Create(componentAppDesc);
|
||||
ASSERT_TRUE(m_systemEntity != nullptr);
|
||||
m_app->AddEntity(m_systemEntity);
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
AZ::Data::AssetManager::Descriptor desc;
|
||||
AZ::Data::AssetManager::Create(desc);
|
||||
m_mockHandler = new ImageAssetMockAssetHandler();
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid<GradientSignal::ImageAsset>());
|
||||
}
|
||||
|
||||
void GradientSignalBaseFixture::TearDownCoreSystems()
|
||||
{
|
||||
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<AZ::ThreadPoolAllocator>::Destroy();
|
||||
|
||||
m_app->Destroy();
|
||||
m_app.reset();
|
||||
m_systemEntity = nullptr;
|
||||
}
|
||||
|
||||
void GradientSignalTest::TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId)
|
||||
{
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
for (int y = 0; y < size; ++y)
|
||||
{
|
||||
for (int x = 0; x < size; ++x)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
|
||||
const int index = y * size + x;
|
||||
float actualValue = gradientSampler.GetValue(params);
|
||||
float expectedValue = expectedOutput[index];
|
||||
|
||||
EXPECT_NEAR(actualValue, expectedValue, 0.01f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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<MockShapeComponent>(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::RunGetValueBenchmark(benchmark::State& state)
|
||||
{
|
||||
// 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));
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Tests/GradientSignalTestMocks.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// Base test fixture used for GradientSignal unit tests and benchmark tests
|
||||
class GradientSignalBaseFixture
|
||||
{
|
||||
public:
|
||||
void SetupCoreSystems();
|
||||
void TearDownCoreSystems();
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> CreateEntity()
|
||||
{
|
||||
return AZStd::make_unique<AZ::Entity>();
|
||||
}
|
||||
|
||||
void ActivateEntity(AZ::Entity* entity)
|
||||
{
|
||||
entity->Init();
|
||||
entity->Activate();
|
||||
}
|
||||
|
||||
template<typename Component, typename Configuration>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
|
||||
{
|
||||
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>(config);
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity)
|
||||
{
|
||||
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::ComponentApplication> m_app;
|
||||
AZ::Entity* m_systemEntity = nullptr;
|
||||
ImageAssetMockAssetHandler* m_mockHandler = nullptr;
|
||||
};
|
||||
|
||||
struct GradientSignalTest
|
||||
: public GradientSignalBaseFixture
|
||||
, public UnitTest::AllocatorsTestFixture
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
UnitTest::AllocatorsTestFixture::SetUp();
|
||||
SetupCoreSystems();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TearDownCoreSystems();
|
||||
UnitTest::AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId);
|
||||
};
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
class GradientSignalBenchmarkFixture
|
||||
: public GradientSignalBaseFixture
|
||||
, public UnitTest::AllocatorsBenchmarkFixture
|
||||
, public UnitTest::TraceBusRedirector
|
||||
{
|
||||
public:
|
||||
void internalSetUp(const benchmark::State& state)
|
||||
{
|
||||
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 RunGetValueBenchmark(benchmark::State& state);
|
||||
|
||||
protected:
|
||||
void SetUp(const benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
void SetUp(benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
|
||||
void TearDown(const benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
void TearDown(benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> m_testEntity;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <Tests/GradientSignalTestMocks.h>
|
||||
|
||||
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);
|
||||
|
||||
size_t value = 0;
|
||||
AZStd::hash_combine(value, seed);
|
||||
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
for (AZ::u32 y = 0; y < height; ++y)
|
||||
{
|
||||
AZStd::hash_combine(value, x);
|
||||
AZStd::hash_combine(value, y);
|
||||
imageData->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const AZ::u8 pixelValue = 255;
|
||||
|
||||
// Image data should be stored inverted on the y axis relative to our engine, so loop backwards through y.
|
||||
for (int y = static_cast<int>(height) - 1; y >= 0; --y)
|
||||
{
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
if ((x == static_cast<int>(pixelX)) && (y == static_cast<int>(pixelY)))
|
||||
{
|
||||
imageData->m_imageData.push_back(pixelValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageData->m_imageData.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,90 +8,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientPreviewContextRequestBus.h>
|
||||
#include <GradientSignal/GradientSampler.h>
|
||||
#include <GradientSignal/ImageAsset.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
|
||||
#include <SurfaceData/Tests/SurfaceDataTestMocks.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
struct GradientSignalTest
|
||||
: public ::testing::Test
|
||||
// Mock asset handler for GradientSignal::ImageAsset that we can use in unit tests to pretend to load an image asset with.
|
||||
// Also includes utility functions for creating image assets with specific testable patterns.
|
||||
struct ImageAssetMockAssetHandler : public AZ::Data::AssetHandler
|
||||
{
|
||||
protected:
|
||||
AZ::ComponentApplication m_app;
|
||||
AZ::Entity* m_systemEntity = nullptr;
|
||||
//! Creates a deterministically random set of pixel data as an ImageAsset.
|
||||
//! \param width The width of the ImageAsset
|
||||
//! \param height The height of the ImageAsset
|
||||
//! \param seed The random seed to use for generating the random data
|
||||
//! \return The ImageAsset in a loaded ready state
|
||||
static AZ::Data::Asset<GradientSignal::ImageAsset> CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed);
|
||||
|
||||
void SetUp() override
|
||||
//! Creates an ImageAsset where all the pixels are 0 except for the one pixel at the given coordinates, which is set to 1.
|
||||
//! \param width The width of the ImageAsset
|
||||
//! \param height The height of the ImageAsset
|
||||
//! \param pixelX The X coordinate of the pixel to set to 1
|
||||
//! \param pixelY The Y coordinate of the pixel to set to 1
|
||||
//! \return The ImageAsset in a loaded ready state
|
||||
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::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 128 * 1024 * 1024;
|
||||
m_systemEntity = m_app.Create(appDesc);
|
||||
m_app.AddEntity(m_systemEntity);
|
||||
return AZ::Data::AssetPtr();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
m_app.Destroy();
|
||||
m_systemEntity = nullptr;
|
||||
}
|
||||
|
||||
void TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId)
|
||||
{
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
for(int y = 0; y < size; ++y)
|
||||
if (ptr)
|
||||
{
|
||||
for (int x = 0; x < size; ++x)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
|
||||
const int index = y * size + x;
|
||||
float actualValue = gradientSampler.GetValue(params);
|
||||
float expectedValue = expectedOutput[index];
|
||||
|
||||
EXPECT_NEAR(actualValue, expectedValue, 0.01f);
|
||||
}
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> CreateEntity()
|
||||
void GetHandledAssetTypes([[maybe_unused]] AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
return AZStd::make_unique<AZ::Entity>();
|
||||
}
|
||||
|
||||
void ActivateEntity(AZ::Entity* entity)
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) override
|
||||
{
|
||||
entity->Init();
|
||||
EXPECT_EQ(AZ::Entity::State::Init, entity->GetState());
|
||||
|
||||
entity->Activate();
|
||||
EXPECT_EQ(AZ::Entity::State::Active, entity->GetState());
|
||||
}
|
||||
|
||||
template <typename Component, typename Configuration>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
|
||||
{
|
||||
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>(config);
|
||||
}
|
||||
|
||||
template <typename Component>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity)
|
||||
{
|
||||
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>();
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/GradientSignalTestFixtures.cpp
|
||||
Tests/EditorGradientSignalPreviewTests.cpp
|
||||
)
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/GradientSignalBenchmarks.cpp
|
||||
Tests/GradientSignalImageTests.cpp
|
||||
Tests/GradientSignalReferencesTests.cpp
|
||||
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