GradientSignalBenchmarks.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #ifdef HAVE_BENCHMARK
  9. #include <Tests/GradientSignalTestFixtures.h>
  10. #include <Tests/GradientSignalTestHelpers.h>
  11. #include <AzTest/AzTest.h>
  12. #include <AzCore/Memory/PoolAllocator.h>
  13. #include <AzCore/Math/Vector2.h>
  14. #include <AzCore/UnitTest/TestTypes.h>
  15. #include <AzFramework/Asset/AssetCatalogBus.h>
  16. #include <AzFramework/Components/TransformComponent.h>
  17. #include <GradientSignal/Components/ConstantGradientComponent.h>
  18. #include <GradientSignal/Components/GradientSurfaceDataComponent.h>
  19. #include <LmbrCentral/Shape/BoxShapeComponentBus.h>
  20. #include <LmbrCentral/Shape/SphereShapeComponentBus.h>
  21. #include <SurfaceData/Components/SurfaceDataShapeComponent.h>
  22. #include <SurfaceData/Components/SurfaceDataSystemComponent.h>
  23. namespace UnitTest
  24. {
  25. class GradientGetValues : public GradientSignalBenchmarkFixture
  26. {
  27. public:
  28. // Create an arbitrary size shape for creating our gradients for benchmark runs.
  29. const float TestShapeHalfBounds = 128.0f;
  30. };
  31. // --------------------------------------------------------------------------------------
  32. // Base Gradients
  33. BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state)
  34. {
  35. auto entity = BuildTestConstantGradient(TestShapeHalfBounds);
  36. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  37. }
  38. BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state)
  39. {
  40. auto entity = BuildTestImageGradient(TestShapeHalfBounds);
  41. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  42. }
  43. BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state)
  44. {
  45. auto entity = BuildTestPerlinGradient(TestShapeHalfBounds);
  46. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  47. }
  48. BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state)
  49. {
  50. auto entity = BuildTestRandomGradient(TestShapeHalfBounds);
  51. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  52. }
  53. BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state)
  54. {
  55. auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds);
  56. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  57. }
  58. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient);
  59. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ImageGradient);
  60. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PerlinGradient);
  61. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_RandomGradient);
  62. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ShapeAreaFalloffGradient);
  63. // --------------------------------------------------------------------------------------
  64. // Gradient Modifiers
  65. BENCHMARK_DEFINE_F(GradientGetValues, BM_DitherGradient)(benchmark::State& state)
  66. {
  67. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  68. auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
  69. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  70. }
  71. BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state)
  72. {
  73. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  74. auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId());
  75. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  76. }
  77. BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state)
  78. {
  79. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  80. auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId());
  81. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  82. }
  83. BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state)
  84. {
  85. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  86. auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds);
  87. auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId());
  88. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  89. }
  90. BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state)
  91. {
  92. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  93. auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId());
  94. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  95. }
  96. BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state)
  97. {
  98. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  99. auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId());
  100. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  101. }
  102. BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state)
  103. {
  104. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  105. auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId());
  106. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  107. }
  108. BENCHMARK_DEFINE_F(GradientGetValues, BM_ThresholdGradient)(benchmark::State& state)
  109. {
  110. auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds);
  111. auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId());
  112. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  113. }
  114. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient);
  115. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_InvertGradient);
  116. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_LevelsGradient);
  117. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_MixedGradient);
  118. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_PosterizeGradient);
  119. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ReferenceGradient);
  120. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SmoothStepGradient);
  121. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ThresholdGradient);
  122. // --------------------------------------------------------------------------------------
  123. // Surface Gradients
  124. BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceAltitudeGradient)(benchmark::State& state)
  125. {
  126. auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds);
  127. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  128. }
  129. BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state)
  130. {
  131. auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds);
  132. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  133. }
  134. BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state)
  135. {
  136. auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds);
  137. GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId());
  138. }
  139. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient);
  140. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceMaskGradient);
  141. GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceSlopeGradient);
  142. // --------------------------------------------------------------------------------------
  143. // Gradient Surface Data
  144. class GradientSurfaceData : public GradientSignalBenchmarkFixture
  145. {
  146. public:
  147. /* To benchmark the GradientSurfaceDataComponent, we need to create a surface provider in the world, then use
  148. the GradientSurfaceDataComponent to modify the surface points.
  149. For the surface provider, we create a flat box centered in XY that's the XY size of the world.
  150. For the GradientSurfaceDataComponent, we'll use a constant gradient as its input, and a sphere centered in XY that's
  151. the XY size of the world as its constrained bounds.
  152. Every surface point within the sphere will have the tags from the provider and the modifier, and every point outside the
  153. sphere will only have the provider tags.
  154. */
  155. AZStd::vector<AZStd::unique_ptr<AZ::Entity>> CreateBenchmarkEntities(float worldSize)
  156. {
  157. AZStd::vector<AZStd::unique_ptr<AZ::Entity>> testEntities;
  158. float halfWorldSize = worldSize / 2.0f;
  159. // Create a large flat box with 2 provider tags.
  160. {
  161. AZStd::unique_ptr<AZ::Entity> surface = AZStd::make_unique<AZ::Entity>();
  162. AZ::Vector3 worldPos(halfWorldSize, halfWorldSize, 10.0f);
  163. auto transform = surface->CreateComponent<AzFramework::TransformComponent>();
  164. transform->SetWorldTM(AZ::Transform::CreateTranslation(worldPos));
  165. LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(worldSize, worldSize, 1.0f));
  166. auto shapeComponent = surface->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
  167. shapeComponent->SetConfiguration(boxConfig);
  168. SurfaceData::SurfaceDataShapeConfig surfaceConfig;
  169. surfaceConfig.m_providerTags.push_back(SurfaceData::SurfaceTag("surface1"));
  170. surfaceConfig.m_providerTags.push_back(SurfaceData::SurfaceTag("surface2"));
  171. surface->CreateComponent<SurfaceData::SurfaceDataShapeComponent>(surfaceConfig);
  172. surface->Init();
  173. surface->Activate();
  174. testEntities.push_back(AZStd::move(surface));
  175. }
  176. // Create a large sphere with a constant gradient and a GradientSurfaceDataComponent.
  177. {
  178. AZStd::unique_ptr<AZ::Entity> modifier = AZStd::make_unique<AZ::Entity>();
  179. AZ::Vector3 worldPos(halfWorldSize, halfWorldSize, 10.0f);
  180. auto transform = modifier->CreateComponent<AzFramework::TransformComponent>();
  181. transform->SetWorldTM(AZ::Transform::CreateTranslation(worldPos));
  182. GradientSignal::ConstantGradientConfig gradientConfig;
  183. gradientConfig.m_value = 0.75f;
  184. modifier->CreateComponent<GradientSignal::ConstantGradientComponent>(gradientConfig);
  185. LmbrCentral::SphereShapeConfig sphereConfig;
  186. sphereConfig.m_radius = halfWorldSize;
  187. auto shapeComponent = modifier->CreateComponent(LmbrCentral::SphereShapeComponentTypeId);
  188. shapeComponent->SetConfiguration(sphereConfig);
  189. GradientSignal::GradientSurfaceDataConfig modifierConfig;
  190. modifierConfig.m_shapeConstraintEntityId = modifier->GetId();
  191. modifierConfig.m_modifierTags.push_back(SurfaceData::SurfaceTag("modifier1"));
  192. modifierConfig.m_modifierTags.push_back(SurfaceData::SurfaceTag("modifier2"));
  193. modifier->CreateComponent<GradientSignal::GradientSurfaceDataComponent>(modifierConfig);
  194. modifier->Init();
  195. modifier->Activate();
  196. testEntities.push_back(AZStd::move(modifier));
  197. }
  198. return testEntities;
  199. }
  200. SurfaceData::SurfaceTagVector CreateBenchmarkTagFilterList()
  201. {
  202. SurfaceData::SurfaceTagVector tagFilterList;
  203. tagFilterList.emplace_back("surface1");
  204. tagFilterList.emplace_back("surface2");
  205. tagFilterList.emplace_back("modifier1");
  206. tagFilterList.emplace_back("modifier2");
  207. return tagFilterList;
  208. }
  209. };
  210. BENCHMARK_DEFINE_F(GradientSurfaceData, BM_GetSurfacePoints)(benchmark::State& state)
  211. {
  212. AZ_PROFILE_FUNCTION(Entity);
  213. // Create our benchmark world
  214. const float worldSize = aznumeric_cast<float>(state.range(0));
  215. AZStd::vector<AZStd::unique_ptr<AZ::Entity>> benchmarkEntities = CreateBenchmarkEntities(worldSize);
  216. SurfaceData::SurfaceTagVector filterTags = CreateBenchmarkTagFilterList();
  217. // Query every point in our world at 1 meter intervals.
  218. for ([[maybe_unused]] auto _ : state)
  219. {
  220. // This is declared outside the loop so that the list of points doesn't fully reallocate on every query.
  221. SurfaceData::SurfacePointList points;
  222. for (float y = 0.0f; y < worldSize; y += 1.0f)
  223. {
  224. for (float x = 0.0f; x < worldSize; x += 1.0f)
  225. {
  226. AZ::Vector3 queryPosition(x, y, 0.0f);
  227. points.Clear();
  228. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->GetSurfacePoints(queryPosition, filterTags, points);
  229. benchmark::DoNotOptimize(points);
  230. }
  231. }
  232. }
  233. }
  234. BENCHMARK_DEFINE_F(GradientSurfaceData, BM_GetSurfacePointsFromRegion)(benchmark::State& state)
  235. {
  236. AZ_PROFILE_FUNCTION(Entity);
  237. // Create our benchmark world
  238. float worldSize = aznumeric_cast<float>(state.range(0));
  239. AZStd::vector<AZStd::unique_ptr<AZ::Entity>> benchmarkEntities = CreateBenchmarkEntities(worldSize);
  240. SurfaceData::SurfaceTagVector filterTags = CreateBenchmarkTagFilterList();
  241. // Query every point in our world at 1 meter intervals.
  242. for ([[maybe_unused]] auto _ : state)
  243. {
  244. SurfaceData::SurfacePointList points;
  245. AZ::Aabb inRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(0.0f), AZ::Vector3(worldSize));
  246. AZ::Vector2 stepSize(1.0f);
  247. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->GetSurfacePointsFromRegion(inRegion, stepSize, filterTags, points);
  248. benchmark::DoNotOptimize(points);
  249. }
  250. }
  251. BENCHMARK_DEFINE_F(GradientSurfaceData, BM_GetSurfacePointsFromList)(benchmark::State& state)
  252. {
  253. AZ_PROFILE_FUNCTION(Entity);
  254. // Create our benchmark world
  255. const float worldSize = aznumeric_cast<float>(state.range(0));
  256. const int64_t worldSizeInt = state.range(0);
  257. AZStd::vector<AZStd::unique_ptr<AZ::Entity>> benchmarkEntities = CreateBenchmarkEntities(worldSize);
  258. SurfaceData::SurfaceTagVector filterTags = CreateBenchmarkTagFilterList();
  259. // Query every point in our world at 1 meter intervals.
  260. for ([[maybe_unused]] auto _ : state)
  261. {
  262. AZStd::vector<AZ::Vector3> queryPositions;
  263. queryPositions.reserve(worldSizeInt * worldSizeInt);
  264. for (float y = 0.0f; y < worldSize; y += 1.0f)
  265. {
  266. for (float x = 0.0f; x < worldSize; x += 1.0f)
  267. {
  268. queryPositions.emplace_back(x, y, 0.0f);
  269. }
  270. }
  271. SurfaceData::SurfacePointList points;
  272. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->GetSurfacePointsFromList(queryPositions, filterTags, points);
  273. benchmark::DoNotOptimize(points);
  274. }
  275. }
  276. BENCHMARK_REGISTER_F(GradientSurfaceData, BM_GetSurfacePoints)
  277. ->Arg(1024)
  278. ->Arg(2048)
  279. ->Unit(::benchmark::kMillisecond);
  280. BENCHMARK_REGISTER_F(GradientSurfaceData, BM_GetSurfacePointsFromRegion)
  281. ->Arg(1024)
  282. ->Arg(2048)
  283. ->Unit(::benchmark::kMillisecond);
  284. BENCHMARK_REGISTER_F(GradientSurfaceData, BM_GetSurfacePointsFromList)
  285. ->Arg(1024)
  286. ->Arg(2048)
  287. ->Unit(::benchmark::kMillisecond);
  288. #endif
  289. }