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:
Mike Balfour
2022-01-07 12:12:09 -06:00
committed by GitHub
parent 8503915cdd
commit 7123ed18be
11 changed files with 466 additions and 78 deletions
+22
View File
@@ -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
)