TerrainSystemBenchmarks.cpp 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  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 <AzCore/Component/ComponentApplication.h>
  10. #include <AzCore/Component/Entity.h>
  11. #include <AzCore/Component/TransformBus.h>
  12. #include <AzCore/Math/Random.h>
  13. #include <AzCore/Memory/PoolAllocator.h>
  14. #include <AzCore/Jobs/JobManagerComponent.h>
  15. #include <AzCore/std/parallel/semaphore.h>
  16. #include <AzCore/UnitTest/TestTypes.h>
  17. #include <AzFramework/Components/TransformComponent.h>
  18. #include <AzFramework/Terrain/TerrainDataRequestBus.h>
  19. #include <AzTest/AzTest.h>
  20. #include <GradientSignal/Components/RandomGradientComponent.h>
  21. #include <GradientSignal/Components/GradientTransformComponent.h>
  22. #include <GradientSignal/Ebuses/GradientRequestBus.h>
  23. #include <SurfaceData/SurfaceDataTypes.h>
  24. #include <LmbrCentral/Shape/ShapeComponentBus.h>
  25. #include <MockAxisAlignedBoxShapeComponent.h>
  26. #include <TerrainSystem/TerrainSystem.h>
  27. #include <TerrainTestFixtures.h>
  28. #include <benchmark/benchmark.h>
  29. namespace UnitTest
  30. {
  31. using ::testing::NiceMock;
  32. using ::testing::Return;
  33. class TerrainSystemBenchmarkFixture
  34. : public TerrainBenchmarkFixture
  35. {
  36. public:
  37. void RunTerrainApiBenchmark(
  38. benchmark::State& state,
  39. AZStd::function<void(
  40. float queryResolution,
  41. const AZ::Aabb& worldBounds,
  42. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)> ApiCaller)
  43. {
  44. AZ_PROFILE_FUNCTION(Terrain);
  45. // Get the ranges for querying from our benchmark parameters
  46. float boundsRange = aznumeric_cast<float>(state.range(0));
  47. uint32_t numSurfaces = aznumeric_cast<uint32_t>(state.range(1));
  48. AzFramework::Terrain::TerrainDataRequests::Sampler sampler =
  49. static_cast<AzFramework::Terrain::TerrainDataRequests::Sampler>(state.range(2));
  50. // Set up our world bounds and query resolution
  51. AZ::Aabb worldBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-boundsRange / 2.0f), AZ::Vector3(boundsRange / 2.0f));
  52. float queryResolution = 1.0f;
  53. CreateTestTerrainSystem(worldBounds, queryResolution, numSurfaces);
  54. // Call the terrain API we're testing for every height and width in our ranges.
  55. for ([[maybe_unused]] auto stateIterator : state)
  56. {
  57. ApiCaller(queryResolution, worldBounds, sampler);
  58. }
  59. DestroyTestTerrainSystem();
  60. }
  61. void GenerateInputPositionsList(float queryResolution, const AZ::Aabb& worldBounds, AZStd::vector<AZ::Vector3>& positions)
  62. {
  63. const size_t numSamplesX = aznumeric_cast<size_t>(ceil(worldBounds.GetExtents().GetX() / queryResolution));
  64. const size_t numSamplesY = aznumeric_cast<size_t>(ceil(worldBounds.GetExtents().GetY() / queryResolution));
  65. positions.clear();
  66. positions.reserve(numSamplesX * numSamplesY);
  67. for (size_t y = 0; y < numSamplesY; y++)
  68. {
  69. float fy = aznumeric_cast<float>(worldBounds.GetMin().GetY() + (y * queryResolution));
  70. for (size_t x = 0; x < numSamplesX; x++)
  71. {
  72. float fx = aznumeric_cast<float>(worldBounds.GetMin().GetX() + (x * queryResolution));
  73. positions.emplace_back(fx, fy, 0.0f);
  74. }
  75. }
  76. }
  77. };
  78. // This fixture is used for benchmarking the terrain system when using a more complicated setup that relies on surface gradients.
  79. // By using a "Terrain -> Gradient -> Surface Data" setup, we're fully exercising all of those systems and lets us benchmark our
  80. // ability to use all of those systems in parallel when calling multiple simultaneous terrain queries.
  81. class TerrainSurfaceGradientBenchmarkFixture : public TerrainSystemBenchmarkFixture
  82. {
  83. public:
  84. void RunTerrainApiSurfaceBenchmark(
  85. benchmark::State& state,
  86. AZStd::function<void(
  87. float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)> ApiCaller)
  88. {
  89. AZ_PROFILE_FUNCTION(Terrain);
  90. // Get the ranges for querying from our benchmark parameters.
  91. // state.range(1) contains the number of requested surfaces, for consistency with other benchmarks.
  92. // It isn't used for this benchmark though - we only set up one surface because we're testing surface complexity
  93. // with this benchmark instead of surface quantity.
  94. float boundsRange = aznumeric_cast<float>(state.range(0));
  95. AzFramework::Terrain::TerrainDataRequests::Sampler sampler =
  96. static_cast<AzFramework::Terrain::TerrainDataRequests::Sampler>(state.range(2));
  97. // Set up our world bounds and query resolution
  98. AZ::Aabb worldBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-boundsRange / 2.0f), AZ::Vector3(boundsRange / 2.0f));
  99. float queryResolution = 1.0f;
  100. CreateTestTerrainSystemWithSurfaceGradients(worldBounds, queryResolution);
  101. // Call the terrain API we're testing for every height and width in our ranges.
  102. for ([[maybe_unused]] auto stateIterator : state)
  103. {
  104. ApiCaller(queryResolution, worldBounds, sampler);
  105. }
  106. DestroyTestTerrainSystem();
  107. }
  108. };
  109. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetHeight)(benchmark::State& state)
  110. {
  111. // Run the benchmark
  112. RunTerrainApiBenchmark(
  113. state,
  114. []([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  115. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  116. {
  117. float worldMinZ = worldBounds.GetMin().GetZ();
  118. for (float y = worldBounds.GetMin().GetY(); y < worldBounds.GetMax().GetY(); y += 1.0f)
  119. {
  120. for (float x = worldBounds.GetMin().GetX(); x < worldBounds.GetMax().GetX(); x += 1.0f)
  121. {
  122. float terrainHeight = worldMinZ;
  123. bool terrainExists = false;
  124. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  125. terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x, y, sampler, &terrainExists);
  126. benchmark::DoNotOptimize(terrainHeight);
  127. }
  128. }
  129. });
  130. }
  131. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetHeight)
  132. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  133. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  134. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  135. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  136. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  137. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  138. ->Unit(::benchmark::kMillisecond);
  139. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegion)(benchmark::State& state)
  140. {
  141. // Run the benchmark
  142. RunTerrainApiBenchmark(
  143. state,
  144. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  145. {
  146. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  147. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  148. {
  149. benchmark::DoNotOptimize(surfacePoint.m_position.GetZ());
  150. };
  151. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  152. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  153. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  154. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  155. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  156. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, perPositionCallback, sampler);
  157. }
  158. );
  159. }
  160. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegion)
  161. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  162. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  163. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  164. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  165. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  166. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  167. ->Unit(::benchmark::kMillisecond);
  168. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegionAsync)(benchmark::State& state)
  169. {
  170. // Run the benchmark
  171. RunTerrainApiBenchmark(
  172. state,
  173. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  174. {
  175. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  176. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  177. {
  178. benchmark::DoNotOptimize(surfacePoint.m_position.GetZ());
  179. };
  180. AZStd::semaphore completionEvent;
  181. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  182. {
  183. completionEvent.release();
  184. };
  185. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  186. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  187. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  188. asyncParams->m_completionCallback = completionCallback;
  189. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  190. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  191. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  192. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  193. &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  194. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, perPositionCallback, sampler, asyncParams);
  195. completionEvent.acquire();
  196. }
  197. );
  198. }
  199. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsRegionAsync)
  200. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  201. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  202. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  203. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  204. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  205. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  206. ->Unit(::benchmark::kMillisecond);
  207. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsList)(benchmark::State& state)
  208. {
  209. // Run the benchmark
  210. RunTerrainApiBenchmark(
  211. state,
  212. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  213. {
  214. AZStd::vector<AZ::Vector3> inPositions;
  215. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  216. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  217. {
  218. benchmark::DoNotOptimize(surfacePoint.m_position.GetZ());
  219. };
  220. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  221. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  222. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, perPositionCallback, sampler);
  223. }
  224. );
  225. }
  226. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsList)
  227. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  228. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  229. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  230. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  231. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  232. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  233. ->Unit(::benchmark::kMillisecond);
  234. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsListAsync)(benchmark::State& state)
  235. {
  236. // Run the benchmark
  237. RunTerrainApiBenchmark(
  238. state,
  239. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  240. {
  241. AZStd::vector<AZ::Vector3> inPositions;
  242. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  243. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  244. {
  245. benchmark::DoNotOptimize(surfacePoint.m_position.GetZ());
  246. };
  247. AZStd::semaphore completionEvent;
  248. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  249. {
  250. completionEvent.release();
  251. };
  252. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  253. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  254. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  255. asyncParams->m_completionCallback = completionCallback;
  256. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  257. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  258. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, perPositionCallback, sampler, asyncParams);
  259. completionEvent.acquire();
  260. }
  261. );
  262. }
  263. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessHeightsListAsync)
  264. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  265. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  266. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  267. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  268. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  269. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  270. ->Unit(::benchmark::kMillisecond);
  271. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetNormal)(benchmark::State& state)
  272. {
  273. // Run the benchmark
  274. RunTerrainApiBenchmark(
  275. state,
  276. []([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  277. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  278. {
  279. for (float y = worldBounds.GetMin().GetY(); y < worldBounds.GetMax().GetY(); y += 1.0f)
  280. {
  281. for (float x = worldBounds.GetMin().GetX(); x < worldBounds.GetMax().GetX(); x += 1.0f)
  282. {
  283. AZ::Vector3 terrainNormal;
  284. bool terrainExists = false;
  285. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  286. terrainNormal, &AzFramework::Terrain::TerrainDataRequests::GetNormalFromFloats, x, y, sampler, &terrainExists);
  287. benchmark::DoNotOptimize(terrainNormal);
  288. }
  289. }
  290. });
  291. }
  292. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetNormal)
  293. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  294. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  295. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  296. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  297. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  298. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  299. ->Unit(::benchmark::kMillisecond);
  300. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegion)(benchmark::State& state)
  301. {
  302. // Run the benchmark
  303. RunTerrainApiBenchmark(
  304. state,
  305. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  306. {
  307. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  308. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  309. {
  310. benchmark::DoNotOptimize(surfacePoint.m_normal);
  311. };
  312. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  313. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  314. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  315. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  316. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  317. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, perPositionCallback, sampler);
  318. }
  319. );
  320. }
  321. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegion)
  322. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  323. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  324. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  325. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  326. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  327. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  328. ->Unit(::benchmark::kMillisecond);
  329. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegionAsync)(benchmark::State& state)
  330. {
  331. // Run the benchmark
  332. RunTerrainApiBenchmark(
  333. state,
  334. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  335. {
  336. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  337. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  338. {
  339. benchmark::DoNotOptimize(surfacePoint.m_normal);
  340. };
  341. AZStd::semaphore completionEvent;
  342. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  343. {
  344. completionEvent.release();
  345. };
  346. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  347. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  348. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  349. asyncParams->m_completionCallback = completionCallback;
  350. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  351. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  352. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  353. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  354. &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  355. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, perPositionCallback, sampler, asyncParams);
  356. completionEvent.acquire();
  357. }
  358. );
  359. }
  360. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsRegionAsync)
  361. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  362. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  363. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  364. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  365. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  366. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  367. ->Unit(::benchmark::kMillisecond);
  368. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsList)(benchmark::State& state)
  369. {
  370. // Run the benchmark
  371. RunTerrainApiBenchmark(
  372. state,
  373. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  374. {
  375. AZStd::vector<AZ::Vector3> inPositions;
  376. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  377. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  378. {
  379. benchmark::DoNotOptimize(surfacePoint.m_normal);
  380. };
  381. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  382. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  383. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, perPositionCallback, sampler);
  384. }
  385. );
  386. }
  387. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsList)
  388. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  389. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  390. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  391. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  392. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  393. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  394. ->Unit(::benchmark::kMillisecond);
  395. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsListAsync)(benchmark::State& state)
  396. {
  397. // Run the benchmark
  398. RunTerrainApiBenchmark(
  399. state,
  400. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  401. {
  402. AZStd::vector<AZ::Vector3> inPositions;
  403. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  404. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  405. {
  406. benchmark::DoNotOptimize(surfacePoint.m_normal);
  407. };
  408. AZStd::semaphore completionEvent;
  409. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  410. {
  411. completionEvent.release();
  412. };
  413. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  414. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  415. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  416. asyncParams->m_completionCallback = completionCallback;
  417. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  418. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  419. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, perPositionCallback, sampler, asyncParams);
  420. completionEvent.acquire();
  421. }
  422. );
  423. }
  424. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessNormalsListAsync)
  425. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  426. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  427. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  428. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  429. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  430. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  431. ->Unit(::benchmark::kMillisecond);
  432. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetSurfaceWeights)(benchmark::State& state)
  433. {
  434. // Run the benchmark
  435. RunTerrainApiBenchmark(
  436. state,
  437. []([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  438. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  439. {
  440. AzFramework::SurfaceData::SurfaceTagWeightList surfaceWeights;
  441. for (float y = worldBounds.GetMin().GetY(); y < worldBounds.GetMax().GetY(); y += 1.0f)
  442. {
  443. for (float x = worldBounds.GetMin().GetX(); x < worldBounds.GetMax().GetX(); x += 1.0f)
  444. {
  445. bool terrainExists = false;
  446. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  447. &AzFramework::Terrain::TerrainDataRequests::GetSurfaceWeightsFromFloats, x, y, surfaceWeights, sampler,
  448. &terrainExists);
  449. benchmark::DoNotOptimize(surfaceWeights);
  450. }
  451. }
  452. });
  453. }
  454. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetSurfaceWeights)
  455. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  456. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  457. ->Args({ 1024, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  458. ->Args({ 2048, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  459. ->Args({ 1024, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  460. ->Args({ 2048, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  461. ->Unit(::benchmark::kMillisecond);
  462. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegion)(benchmark::State& state)
  463. {
  464. // Run the benchmark
  465. RunTerrainApiBenchmark(
  466. state,
  467. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  468. {
  469. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  470. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  471. {
  472. benchmark::DoNotOptimize(surfacePoint.m_surfaceTags);
  473. };
  474. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  475. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  476. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  477. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  478. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  479. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler);
  480. }
  481. );
  482. }
  483. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegion)
  484. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  485. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  486. ->Args({ 1024, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  487. ->Args({ 2048, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  488. ->Args({ 1024, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  489. ->Args({ 2048, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  490. ->Unit(::benchmark::kMillisecond);
  491. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegionAsync)(benchmark::State& state)
  492. {
  493. // Run the benchmark
  494. RunTerrainApiBenchmark(
  495. state,
  496. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  497. {
  498. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  499. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  500. {
  501. benchmark::DoNotOptimize(surfacePoint.m_surfaceTags);
  502. };
  503. AZStd::semaphore completionEvent;
  504. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  505. {
  506. completionEvent.release();
  507. };
  508. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  509. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  510. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  511. asyncParams->m_completionCallback = completionCallback;
  512. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  513. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  514. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  515. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  516. &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  517. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler, asyncParams);
  518. completionEvent.acquire();
  519. }
  520. );
  521. }
  522. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsRegionAsync)
  523. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  524. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  525. ->Args({ 1024, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  526. ->Args({ 2048, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  527. ->Args({ 1024, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  528. ->Args({ 2048, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  529. ->Unit(::benchmark::kMillisecond);
  530. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsList)(benchmark::State& state)
  531. {
  532. // Run the benchmark
  533. RunTerrainApiBenchmark(
  534. state,
  535. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  536. {
  537. AZStd::vector<AZ::Vector3> inPositions;
  538. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  539. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  540. {
  541. benchmark::DoNotOptimize(surfacePoint.m_surfaceTags);
  542. };
  543. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  544. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  545. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler);
  546. }
  547. );
  548. }
  549. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsList)
  550. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  551. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  552. ->Args({ 1024, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  553. ->Args({ 2048, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  554. ->Args({ 1024, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  555. ->Args({ 2048, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  556. ->Unit(::benchmark::kMillisecond);
  557. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsListAsync)(benchmark::State& state)
  558. {
  559. // Run the benchmark
  560. RunTerrainApiBenchmark(
  561. state,
  562. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  563. {
  564. AZStd::vector<AZ::Vector3> inPositions;
  565. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  566. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  567. {
  568. benchmark::DoNotOptimize(surfacePoint.m_surfaceTags);
  569. };
  570. AZStd::semaphore completionEvent;
  571. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  572. {
  573. completionEvent.release();
  574. };
  575. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  576. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  577. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  578. asyncParams->m_completionCallback = completionCallback;
  579. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  580. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  581. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler, asyncParams);
  582. completionEvent.acquire();
  583. }
  584. );
  585. }
  586. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfaceWeightsListAsync)
  587. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  588. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  589. ->Args({ 1024, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  590. ->Args({ 2048, 2, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  591. ->Args({ 1024, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  592. ->Args({ 2048, 4, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  593. ->Unit(::benchmark::kMillisecond);
  594. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetSurfacePoints)(benchmark::State& state)
  595. {
  596. // Run the benchmark
  597. RunTerrainApiBenchmark(
  598. state,
  599. []([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  600. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  601. {
  602. AzFramework::SurfaceData::SurfacePoint surfacePoint;
  603. for (float y = worldBounds.GetMin().GetY(); y < worldBounds.GetMax().GetY(); y += 1.0f)
  604. {
  605. for (float x = worldBounds.GetMin().GetX(); x < worldBounds.GetMax().GetX(); x += 1.0f)
  606. {
  607. bool terrainExists = false;
  608. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  609. &AzFramework::Terrain::TerrainDataRequests::GetSurfacePointFromFloats, x, y, surfacePoint, sampler,
  610. &terrainExists);
  611. benchmark::DoNotOptimize(surfacePoint);
  612. }
  613. }
  614. });
  615. }
  616. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetSurfacePoints)
  617. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  618. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  619. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  620. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  621. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  622. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  623. ->Unit(::benchmark::kMillisecond);
  624. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegion)(benchmark::State& state)
  625. {
  626. // Run the benchmark
  627. RunTerrainApiBenchmark(
  628. state,
  629. [](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  630. {
  631. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  632. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  633. {
  634. benchmark::DoNotOptimize(surfacePoint);
  635. };
  636. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  637. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  638. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  639. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  640. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  641. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler);
  642. }
  643. );
  644. }
  645. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegion)
  646. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  647. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  648. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  649. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  650. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  651. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  652. ->Unit(::benchmark::kMillisecond);
  653. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegionAsync)(benchmark::State& state)
  654. {
  655. // Run the benchmark
  656. RunTerrainApiBenchmark(
  657. state,
  658. []([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  659. AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  660. {
  661. auto perPositionCallback = []([[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  662. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  663. {
  664. benchmark::DoNotOptimize(surfacePoint);
  665. };
  666. AZStd::semaphore completionEvent;
  667. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  668. {
  669. completionEvent.release();
  670. };
  671. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  672. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  673. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  674. asyncParams->m_completionCallback = completionCallback;
  675. AZ::Vector2 stepSize = AZ::Vector2(queryResolution);
  676. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  677. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(worldBounds, stepSize);
  678. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  679. &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  680. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler, asyncParams);
  681. completionEvent.acquire();
  682. }
  683. );
  684. }
  685. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsRegionAsync)
  686. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  687. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  688. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  689. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  690. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  691. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  692. ->Unit(::benchmark::kMillisecond);
  693. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsList)(benchmark::State& state)
  694. {
  695. // Run the benchmark
  696. RunTerrainApiBenchmark(
  697. state,
  698. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  699. {
  700. AZStd::vector<AZ::Vector3> inPositions;
  701. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  702. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  703. {
  704. benchmark::DoNotOptimize(surfacePoint);
  705. };
  706. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  707. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  708. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler);
  709. }
  710. );
  711. }
  712. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsList)
  713. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  714. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  715. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  716. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  717. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  718. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  719. ->Unit(::benchmark::kMillisecond);
  720. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsListAsync)(benchmark::State& state)
  721. {
  722. // Run the benchmark
  723. RunTerrainApiBenchmark(
  724. state,
  725. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  726. {
  727. AZStd::vector<AZ::Vector3> inPositions;
  728. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  729. auto perPositionCallback = [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  730. {
  731. benchmark::DoNotOptimize(surfacePoint);
  732. };
  733. AZStd::semaphore completionEvent;
  734. auto completionCallback = [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  735. {
  736. completionEvent.release();
  737. };
  738. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams
  739. = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  740. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  741. asyncParams->m_completionCallback = completionCallback;
  742. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  743. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  744. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler, asyncParams);
  745. completionEvent.acquire();
  746. }
  747. );
  748. }
  749. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ProcessSurfacePointsListAsync)
  750. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  751. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  752. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  753. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  754. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  755. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  756. ->Unit(::benchmark::kMillisecond);
  757. // Get timings for how long it takes to run N of the same query at the same time.
  758. // We limit each query to 2 threads to allow multiple queries to run simultaneously.
  759. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_ParallelProcessSurfacePointsListAsync)(benchmark::State& state)
  760. {
  761. // Run the benchmark
  762. RunTerrainApiBenchmark(
  763. state,
  764. [this, state](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  765. {
  766. AZStd::vector<AZ::Vector3> inPositions;
  767. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  768. auto perPositionCallback =
  769. [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  770. {
  771. benchmark::DoNotOptimize(surfacePoint);
  772. };
  773. constexpr uint32_t maxParallelQueries = 16;
  774. AZStd::binary_semaphore completionEvents[maxParallelQueries];
  775. uint32_t numParallelQueries = AZStd::min(aznumeric_cast<uint32_t>(state.range(3)), maxParallelQueries);
  776. for (uint32_t query = 0; query < numParallelQueries; query++)
  777. {
  778. auto completionCallback =
  779. [&completionEvents, query](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  780. {
  781. completionEvents[query].release();
  782. };
  783. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams =
  784. AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  785. // Limit each query to 2 threads so that it's possible to run multiple of them simultaneously.
  786. asyncParams->m_desiredNumberOfJobs = 2;
  787. asyncParams->m_completionCallback = completionCallback;
  788. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  789. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  790. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback,
  791. sampler, asyncParams);
  792. }
  793. for (uint32_t query = 0; query < numParallelQueries; query++)
  794. {
  795. completionEvents[query].acquire();
  796. }
  797. });
  798. }
  799. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_ParallelProcessSurfacePointsListAsync)
  800. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 1 })
  801. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 2 })
  802. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 3 })
  803. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 4 })
  804. ->Unit(::benchmark::kMillisecond);
  805. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetClosestIntersectionRandom)(benchmark::State& state)
  806. {
  807. // Run the benchmark
  808. const uint32_t numRays = aznumeric_cast<uint32_t>(state.range(1));
  809. RunTerrainApiBenchmark(
  810. state,
  811. [numRays]([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  812. [[maybe_unused]] AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  813. {
  814. // Cast rays starting at random positions above the terrain,
  815. // and ending at a random positions below the terrain.
  816. AZ::SimpleLcgRandom random;
  817. AzFramework::RenderGeometry::RayRequest ray;
  818. AzFramework::RenderGeometry::RayResult result;
  819. for (uint32_t i = 0; i < numRays; ++i)
  820. {
  821. ray.m_startWorldPosition.SetX(worldBounds.GetMin().GetX() + (random.GetRandomFloat() * worldBounds.GetXExtent()));
  822. ray.m_startWorldPosition.SetY(worldBounds.GetMin().GetY() + (random.GetRandomFloat() * worldBounds.GetYExtent()));
  823. ray.m_startWorldPosition.SetZ(worldBounds.GetMax().GetZ());
  824. ray.m_endWorldPosition.SetX(worldBounds.GetMin().GetX() + (random.GetRandomFloat() * worldBounds.GetXExtent()));
  825. ray.m_endWorldPosition.SetY(worldBounds.GetMin().GetY() + (random.GetRandomFloat() * worldBounds.GetYExtent()));
  826. ray.m_endWorldPosition.SetZ(worldBounds.GetMin().GetZ());
  827. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  828. result, &AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection, ray);
  829. }
  830. });
  831. }
  832. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetClosestIntersectionRandom)
  833. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  834. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  835. ->Args({ 1024, 10, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  836. ->Args({ 2048, 10, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  837. ->Args({ 1024, 100, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  838. ->Args({ 2048, 100, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  839. ->Args({ 1024, 1000, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  840. ->Args({ 2048, 1000, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  841. ->Unit(::benchmark::kMillisecond);
  842. BENCHMARK_DEFINE_F(TerrainSystemBenchmarkFixture, BM_GetClosestIntersectionWorstCase)(benchmark::State& state)
  843. {
  844. // Run the benchmark
  845. const uint32_t numRays = aznumeric_cast<uint32_t>(state.range(1));
  846. RunTerrainApiBenchmark(
  847. state,
  848. [numRays]([[maybe_unused]] float queryResolution, const AZ::Aabb& worldBounds,
  849. [[maybe_unused]] AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  850. {
  851. // Cast rays starting at an upper corner of the terrain world,
  852. // and ending at the opposite top corner of the terrain world,
  853. // traversing the entire grid without finding an intersection.
  854. AzFramework::RenderGeometry::RayRequest ray;
  855. AzFramework::RenderGeometry::RayResult result;
  856. ray.m_startWorldPosition = worldBounds.GetMax();
  857. ray.m_endWorldPosition = worldBounds.GetMin();
  858. ray.m_endWorldPosition.SetZ(ray.m_startWorldPosition.GetZ());
  859. for (uint32_t i = 0; i < numRays; ++i)
  860. {
  861. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  862. result, &AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection, ray);
  863. }
  864. });
  865. }
  866. BENCHMARK_REGISTER_F(TerrainSystemBenchmarkFixture, BM_GetClosestIntersectionWorstCase)
  867. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  868. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  869. ->Args({ 1024, 10, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  870. ->Args({ 2048, 10, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  871. ->Args({ 1024, 100, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  872. ->Args({ 2048, 100, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  873. ->Args({ 1024, 1000, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  874. ->Args({ 2048, 1000, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  875. ->Unit(::benchmark::kMillisecond);
  876. // Benchmark a single usage of our more complicated terrain setup.
  877. BENCHMARK_DEFINE_F(TerrainSurfaceGradientBenchmarkFixture, BM_ProcessSurfacePointsList_SurfaceGradients)(benchmark::State& state)
  878. {
  879. // Run the benchmark
  880. RunTerrainApiSurfaceBenchmark(
  881. state,
  882. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  883. {
  884. AZStd::vector<AZ::Vector3> inPositions;
  885. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  886. auto perPositionCallback =
  887. [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  888. {
  889. benchmark::DoNotOptimize(surfacePoint);
  890. };
  891. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  892. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  893. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler);
  894. });
  895. }
  896. BENCHMARK_REGISTER_F(TerrainSurfaceGradientBenchmarkFixture, BM_ProcessSurfacePointsList_SurfaceGradients)
  897. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  898. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  899. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  900. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  901. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  902. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  903. ->Unit(::benchmark::kMillisecond);
  904. // Benchmark a single usage of our more complicated terrain setup.
  905. BENCHMARK_DEFINE_F(TerrainSurfaceGradientBenchmarkFixture, BM_ProcessSurfacePointsListAsync_SurfaceGradients)(benchmark::State& state)
  906. {
  907. // Run the benchmark
  908. RunTerrainApiSurfaceBenchmark(
  909. state,
  910. [this](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  911. {
  912. AZStd::vector<AZ::Vector3> inPositions;
  913. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  914. auto perPositionCallback =
  915. [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  916. {
  917. benchmark::DoNotOptimize(surfacePoint);
  918. };
  919. AZStd::semaphore completionEvent;
  920. auto completionCallback =
  921. [&completionEvent](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  922. {
  923. completionEvent.release();
  924. };
  925. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams =
  926. AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  927. asyncParams->m_desiredNumberOfJobs = AzFramework::Terrain::QueryAsyncParams::UseMaxJobs;
  928. asyncParams->m_completionCallback = completionCallback;
  929. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  930. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  931. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback,
  932. sampler, asyncParams);
  933. completionEvent.acquire();
  934. });
  935. }
  936. BENCHMARK_REGISTER_F(TerrainSurfaceGradientBenchmarkFixture, BM_ProcessSurfacePointsListAsync_SurfaceGradients)
  937. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  938. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR) })
  939. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  940. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP) })
  941. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  942. ->Args({ 2048, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT) })
  943. ->Unit(::benchmark::kMillisecond);
  944. // Get timings for how long it takes to run N of the same query at the same time.
  945. // We limit each query to 2 threads to allow multiple queries to run simultaneously.
  946. BENCHMARK_DEFINE_F(TerrainSurfaceGradientBenchmarkFixture, BM_ParallelProcessSurfacePointsListAsync_SurfaceGradients)
  947. (benchmark::State& state)
  948. {
  949. // Run the benchmark
  950. RunTerrainApiSurfaceBenchmark(
  951. state,
  952. [this, state](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  953. {
  954. AZStd::vector<AZ::Vector3> inPositions;
  955. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  956. auto perPositionCallback =
  957. [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  958. {
  959. benchmark::DoNotOptimize(surfacePoint);
  960. };
  961. constexpr uint32_t maxParallelQueries = 16;
  962. AZStd::binary_semaphore completionEvents[maxParallelQueries];
  963. uint32_t numParallelQueries = AZStd::min(aznumeric_cast<uint32_t>(state.range(3)), maxParallelQueries);
  964. for (uint32_t query = 0; query < numParallelQueries; query++)
  965. {
  966. auto completionCallback =
  967. [&completionEvents, query](AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext>)
  968. {
  969. completionEvents[query].release();
  970. };
  971. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> asyncParams =
  972. AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  973. // Limit each query to 2 threads so that it's possible to run multiple of them simultaneously.
  974. asyncParams->m_desiredNumberOfJobs = 2;
  975. asyncParams->m_completionCallback = completionCallback;
  976. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  977. &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, inPositions,
  978. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback,
  979. sampler, asyncParams);
  980. }
  981. for (uint32_t query = 0; query < numParallelQueries; query++)
  982. {
  983. completionEvents[query].acquire();
  984. }
  985. });
  986. }
  987. BENCHMARK_REGISTER_F(TerrainSurfaceGradientBenchmarkFixture, BM_ParallelProcessSurfacePointsListAsync_SurfaceGradients)
  988. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 1 })
  989. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 2 })
  990. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 3 })
  991. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 4 })
  992. ->Unit(::benchmark::kMillisecond);
  993. // Get timings for how long it takes to run N of the same query at the same time.
  994. BENCHMARK_DEFINE_F(TerrainSurfaceGradientBenchmarkFixture, BM_ParallelProcessSurfacePointsList_SurfaceGradients)
  995. (benchmark::State& state)
  996. {
  997. // Run the benchmark
  998. RunTerrainApiSurfaceBenchmark(
  999. state,
  1000. [this, state](float queryResolution, const AZ::Aabb& worldBounds, AzFramework::Terrain::TerrainDataRequests::Sampler sampler)
  1001. {
  1002. AZStd::vector<AZ::Vector3> inPositions;
  1003. GenerateInputPositionsList(queryResolution, worldBounds, inPositions);
  1004. constexpr uint32_t MaxParallelQueries = 16;
  1005. AZStd::thread threads[MaxParallelQueries];
  1006. AZStd::semaphore syncThreads;
  1007. uint32_t numParallelQueries = AZStd::min(aznumeric_cast<uint32_t>(state.range(3)), MaxParallelQueries);
  1008. // Create N threads, each one running a "ProcessSurfacePointsFromList" synchronous terrain query.
  1009. for (uint32_t thread = 0; thread < numParallelQueries; thread++)
  1010. {
  1011. threads[thread] = AZStd::thread(
  1012. [&inPositions, &syncThreads, sampler]()
  1013. {
  1014. auto perPositionCallback =
  1015. [](const AzFramework::SurfaceData::SurfacePoint& surfacePoint, [[maybe_unused]] bool terrainExists)
  1016. {
  1017. benchmark::DoNotOptimize(surfacePoint);
  1018. };
  1019. syncThreads.acquire();
  1020. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  1021. &AzFramework::Terrain::TerrainDataRequests::QueryList, inPositions,
  1022. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback,
  1023. sampler);
  1024. });
  1025. }
  1026. // Now that all threads are created, signal everything to start running in parallel.
  1027. syncThreads.release(numParallelQueries);
  1028. // Wait for the threads to finish.
  1029. for (uint32_t thread = 0; thread < numParallelQueries; thread++)
  1030. {
  1031. threads[thread].join();
  1032. }
  1033. });
  1034. }
  1035. BENCHMARK_REGISTER_F(TerrainSurfaceGradientBenchmarkFixture, BM_ParallelProcessSurfacePointsList_SurfaceGradients)
  1036. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 1 })
  1037. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 2 })
  1038. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 3 })
  1039. ->Args({ 1024, 1, static_cast<int>(AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR), 4 })
  1040. ->Unit(::benchmark::kMillisecond);
  1041. #endif
  1042. }