diff --git a/Assets/Editor/Icons/AssetBrowser/Collapse_All.svg b/Assets/Editor/Icons/AssetBrowser/Collapse_All.svg new file mode 100644 index 0000000000..7c7a7b85bd --- /dev/null +++ b/Assets/Editor/Icons/AssetBrowser/Collapse_All.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py index 8f179f7f50..b5c00a53b7 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py @@ -68,7 +68,7 @@ def ShapeIntersectionFilter_FilterStageToggle(): # Create a new entity as a child of the vegetation area entity with Box Shape box = hydra.Entity("box") box.create_entity(position, ["Box Shape"]) - box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(8.0, 8.0, 1.0)) + box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(5.0, 5.0, 1.0)) # Create a new entity as a child of the vegetation area entity with Cylinder Shape. cylinder = hydra.Entity("cylinder") @@ -80,10 +80,10 @@ def ShapeIntersectionFilter_FilterStageToggle(): # On the Shape Intersection Filter component, click the crosshair button, and add child entities one by one vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id) - result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0) + result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 49), 2.0) Report.result(Tests.instance_count_in_box_shape, result) vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id) - result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0) + result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 121), 2.0) Report.result(Tests.instance_count_in_cylinder_shape, result) # Create a new entity as a child of the area entity with Random Noise Gradient, Gradient Transform Modifier, @@ -98,12 +98,13 @@ def ShapeIntersectionFilter_FilterStageToggle(): # Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id) - # Toggle between PreProcess and PostProcess + # Toggle between PreProcess and PostProcess and validate instances. Validate in a 0.3m wider radius due to position + # offsets vegetation.get_set_test(3, "Configuration|Filter Stage", 1) - result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0) + result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.3, 121), 2.0) Report.result(Tests.preprocess_instance_count, result) vegetation.get_set_test(3, "Configuration|Filter Stage", 2) - result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0) + result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.3, 122), 2.0) Report.result(Tests.postprocess_instance_count, result) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py index af1c187817..5b1e504442 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py @@ -131,7 +131,6 @@ class TestAutomation_PrefabNotEnabled(EditorTestSuite): class test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(EditorParallelTest): from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module - @pytest.mark.skip("https://github.com/o3de/o3de/issues/6973") class test_ShapeIntersectionFilter_FilterStageToggle(EditorParallelTest): from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module diff --git a/Code/Editor/AssetImporter/AssetImporterManager/AssetImporterManager.cpp b/Code/Editor/AssetImporter/AssetImporterManager/AssetImporterManager.cpp index baa287e47f..73c3d6f9ed 100644 --- a/Code/Editor/AssetImporter/AssetImporterManager/AssetImporterManager.cpp +++ b/Code/Editor/AssetImporter/AssetImporterManager/AssetImporterManager.cpp @@ -191,6 +191,7 @@ void AssetImporterManager::OnBrowseDestinationFilePath(QLineEdit* destinationLin fileDialog.setViewMode(QFileDialog::List); fileDialog.setWindowModality(Qt::WindowModality::ApplicationModal); fileDialog.setWindowTitle(tr("Select import destination")); + fileDialog.setFileMode(QFileDialog::Directory); QSettings settings; QString currentDestination = settings.value(AssetImporterManagerPrivate::g_selectDestinationFilesPath).toString(); diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp index a7faea36f6..36e08982a7 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp @@ -32,6 +32,15 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView); +namespace AzToolsFramework +{ + namespace AssetBrowser + { + static constexpr const char* CollapseAllIcon = "Assets/Editor/Icons/AssetBrowser/Collapse_All.svg"; + static constexpr const char* MenuIcon = ":/Menu/menu.svg"; + } // namespace AssetBrowser +} // namespace AzToolsFramework + class ListenerForShowAssetEditorEvent : public QObject , private AzToolsFramework::EditorEvents::Bus::Handler @@ -87,10 +96,21 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent) m_assetBrowserModel->SetFilterModel(m_filterModel.data()); + m_ui->m_collapseAllButton->setAutoRaise(true); // hover highlight + m_ui->m_collapseAllButton->setIcon(QIcon(AzAssetBrowser::CollapseAllIcon)); + + connect( + m_ui->m_collapseAllButton, &QToolButton::clicked, this, + [this]() + { + m_ui->m_assetBrowserTreeViewWidget->collapseAll(); + }); + if (ed_useNewAssetBrowserTableView) { m_ui->m_toggleDisplayViewBtn->setVisible(true); - m_ui->m_toggleDisplayViewBtn->setIcon(QIcon(":/Menu/menu.svg")); + m_ui->m_toggleDisplayViewBtn->setAutoRaise(true); + m_ui->m_toggleDisplayViewBtn->setIcon(QIcon(AzAssetBrowser::MenuIcon)); m_tableModel->setFilterRole(Qt::DisplayRole); m_tableModel->setSourceModel(m_filterModel.data()); diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui index a345438aed..2cc7c57ccd 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui @@ -72,6 +72,22 @@ + + + + Qt::ClickFocus + + + + + + 3 + + + + + + @@ -143,15 +159,6 @@ true - - false - - - true - - - false - diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h index e8efce1133..e99f29e051 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 1 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp index 92a80b0d9a..e89c46bce7 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp @@ -6,74 +6,121 @@ * */ +#include +#include #include #include -#include #include -#include -namespace AZ::Debug::Platform +namespace AZ::Debug { #if defined(AZ_ENABLE_DEBUG_TOOLS) - bool performDebuggerDetection() + void ExceptionHandler(int signal); +#endif + + constexpr int MaxMessageLength = 4096; + constexpr int MaxStackLines = 100; + + namespace Platform { - AZ::IO::SystemFile processStatusFile; - if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY)) +#if defined(AZ_ENABLE_DEBUG_TOOLS) + bool performDebuggerDetection() { - return false; - } - - char buffer[4096]; - AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer); - - const AZStd::string_view processStatusView(buffer, buffer + numRead); - constexpr AZStd::string_view tracerPidString = "TracerPid:"; - const size_t tracerPidOffset = processStatusView.find(tracerPidString); - if (tracerPidOffset == AZStd::string_view::npos) - { - return false; - } - for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i) - { - if (!::isspace(processStatusView[i])) + AZ::IO::SystemFile processStatusFile; + if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY)) { - return processStatusView[i] != '0'; + return false; + } + + char buffer[MaxMessageLength]; + AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer); + + const AZStd::string_view processStatusView(buffer, buffer + numRead); + constexpr AZStd::string_view tracerPidString = "TracerPid:"; + const size_t tracerPidOffset = processStatusView.find(tracerPidString); + if (tracerPidOffset == AZStd::string_view::npos) + { + return false; + } + for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i) + { + if (processStatusView[i] != ' ') + { + return processStatusView[i] != '0'; + } + } + return false; + } + + bool IsDebuggerPresent() + { + static bool s_detectionPerformed = false; + static bool s_debuggerDetected = false; + if (!s_detectionPerformed) + { + s_debuggerDetected = performDebuggerDetection(); + s_detectionPerformed = true; + } + return s_debuggerDetected; + } + + bool AttachDebugger() + { + // Not supported yet + AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet"); + return false; + } + + void HandleExceptions(bool isEnabled) + { + if (isEnabled) + { + signal(SIGSEGV, ExceptionHandler); + signal(SIGTRAP, ExceptionHandler); + signal(SIGILL, ExceptionHandler); + } + else + { + signal(SIGSEGV, SIG_DFL); + signal(SIGTRAP, SIG_DFL); + signal(SIGILL, SIG_DFL); } } - return false; - } - bool IsDebuggerPresent() - { - static bool s_detectionPerformed = false; - static bool s_debuggerDetected = false; - if (!s_detectionPerformed) + void DebugBreak() { - s_debuggerDetected = performDebuggerDetection(); - s_detectionPerformed = true; + raise(SIGINT); } - return s_debuggerDetected; - } - - bool AttachDebugger() - { - // Not supported yet - AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet"); - return false; - } - - void HandleExceptions(bool) - {} - - void DebugBreak() - { - raise(SIGINT); - } #endif // AZ_ENABLE_DEBUG_TOOLS - void Terminate(int exitCode) + void Terminate(int exitCode) + { + _exit(exitCode); + } + } // namespace Platform + +#if defined(AZ_ENABLE_DEBUG_TOOLS) + void ExceptionHandler(int signal) { - _exit(exitCode); + char message[MaxMessageLength]; + // Trace::RawOutput + Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n"); + azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal)); + Debug::Trace::Instance().RawOutput(nullptr, message); + + StackFrame frames[MaxStackLines]; + SymbolStorage::StackLine stackLines[MaxStackLines]; + SymbolStorage decoder; + const unsigned int numberOfFrames = StackRecorder::Record(frames, MaxStackLines); + decoder.DecodeFrames(frames, numberOfFrames, stackLines); + for (int i = 0; i < numberOfFrames; ++i) + { + azsnprintf(message, MaxMessageLength, "%s \n", stackLines[i]); + Debug::Trace::Instance().RawOutput(nullptr, message); + } + Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n"); } -} // namespace AZ::Debug::Platform +#endif + +} // namespace AZ::Debug diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h index 59d5f3c5ed..e5e52995a1 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h index 1a3d0663e1..9a6c76fe2d 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h index 1a83aba267..71d6b395c5 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE INVALID_RETURN_VALUE #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 1 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0 #define AZ_TRAIT_USE_POSIX_STRERROR_R 0 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 1 #define AZ_TRAIT_USE_WINDOWS_FILE_API 1 diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h index 7a75af71fb..11a0ba84e0 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h @@ -99,7 +99,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 09bbc3773a..f3f9442322 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -115,43 +115,6 @@ extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExce #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif -#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - -#include -#include -void CryEngineSignalHandler(int signal) -{ - char resolvedPath[_MAX_PATH]; - - // it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir) - if (AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath("@log@/crash.log", resolvedPath, _MAX_PATH)) - { - fprintf(stderr, "Crash Signal Handler - logged to %s\n", resolvedPath); - FILE* file = fopen(resolvedPath, "a"); - if (file) - { - char sTime[128]; - time_t ltime; - time(<ime); - struct tm* today = localtime(<ime); - strftime(sTime, 40, "<%Y-%m-%d %H:%M:%S> ", today); - fprintf(file, "%s: Error: signal %s:\n", sTime, strsignal(signal)); - fflush(file); - void* array[100]; - int s = backtrace(array, 100); - backtrace_symbols_fd(array, s, fileno(file)); - fclose(file); - CryLogAlways("Successfully recorded crash file: '%s'", resolvedPath); - abort(); - } - } - - CryLogAlways("Could not record crash file..."); - abort(); -} - -#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - ////////////////////////////////////////////////////////////////////////// #define DEFAULT_LOG_FILENAME "@log@/Log.txt" @@ -697,11 +660,6 @@ public: ///////////////////////////////////////////////////////////////////////////////// bool CSystem::Init(const SSystemInitParams& startupParams) { -#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - signal(SIGSEGV, CryEngineSignalHandler); - signal(SIGTRAP, CryEngineSignalHandler); - signal(SIGILL, CryEngineSignalHandler); -#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 7c436a3a70..60959d4090 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -408,7 +408,7 @@ namespace O3DE::ProjectManager } // check if engine path is registered - auto allEngines = m_manifest.attr("get_engines")(); + auto allEngines = m_manifest.attr("get_manifest_engines")(); if (pybind11::isinstance(allEngines)) { const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath)); @@ -891,7 +891,7 @@ namespace O3DE::ProjectManager bool result = ExecuteWithLock([&] { // external projects - for (auto path : m_manifest.attr("get_projects")()) + for (auto path : m_manifest.attr("get_manifest_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/gem.json b/Gems/Atom/Asset/ImageProcessingAtom/gem.json index c2af4b7e7e..baa46268b3 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/gem.json +++ b/Gems/Atom/Asset/ImageProcessingAtom/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Image processing for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/Bootstrap/gem.json b/Gems/Atom/Bootstrap/gem.json index 543efe0f34..726021235f 100644 --- a/Gems/Atom/Bootstrap/gem.json +++ b/Gems/Atom/Bootstrap/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Atom Bootstrap", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/Component/DebugCamera/gem.json b/Gems/Atom/Component/DebugCamera/gem.json index 74d88a21b6..678cce3045 100644 --- a/Gems/Atom/Component/DebugCamera/gem.json +++ b/Gems/Atom/Component/DebugCamera/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Debug Camera component for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/Feature/Common/gem.json b/Gems/Atom/Feature/Common/gem.json index f4c936dc4a..d915c55b1d 100644 --- a/Gems/Atom/Feature/Common/gem.json +++ b/Gems/Atom/Feature/Common/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Common features for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RHI/DX12/gem.json b/Gems/Atom/RHI/DX12/gem.json index 803ae4f4d0..67d91790a9 100644 --- a/Gems/Atom/RHI/DX12/gem.json +++ b/Gems/Atom/RHI/DX12/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "DX12 RHI for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RHI/Metal/gem.json b/Gems/Atom/RHI/Metal/gem.json index 0257048bd3..555b86523c 100644 --- a/Gems/Atom/RHI/Metal/gem.json +++ b/Gems/Atom/RHI/Metal/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Metal RHI for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RHI/Null/gem.json b/Gems/Atom/RHI/Null/gem.json index 1ea2eb4cb0..d531aa4ab5 100644 --- a/Gems/Atom/RHI/Null/gem.json +++ b/Gems/Atom/RHI/Null/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Atom Null RHI", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RHI/Vulkan/gem.json b/Gems/Atom/RHI/Vulkan/gem.json index 508ad85c75..5d49085ac5 100644 --- a/Gems/Atom/RHI/Vulkan/gem.json +++ b/Gems/Atom/RHI/Vulkan/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Vulcan RHI for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RHI/gem.json b/Gems/Atom/RHI/gem.json index 858a64fc17..49ec18ea53 100644 --- a/Gems/Atom/RHI/gem.json +++ b/Gems/Atom/RHI/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "RHI for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/RPI/gem.json b/Gems/Atom/RPI/gem.json index 0acef5179b..fe135c3e90 100644 --- a/Gems/Atom/RPI/gem.json +++ b/Gems/Atom/RPI/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "RPI for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/Atom/Tools/AtomToolsFramework/gem.json b/Gems/Atom/Tools/AtomToolsFramework/gem.json index 6e5a7b311a..a86244e7cc 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/gem.json +++ b/Gems/Atom/Tools/AtomToolsFramework/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Tools Framework for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/AtomBridge/gem.json b/Gems/AtomLyIntegration/AtomBridge/gem.json index 5a8512c90d..87a10aa6d3 100644 --- a/Gems/AtomLyIntegration/AtomBridge/gem.json +++ b/Gems/AtomLyIntegration/AtomBridge/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Atom Bridge", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/AtomFont/gem.json b/Gems/AtomLyIntegration/AtomFont/gem.json index d979509059..4f5ba75ff2 100644 --- a/Gems/AtomLyIntegration/AtomFont/gem.json +++ b/Gems/AtomLyIntegration/AtomFont/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Font Rendering for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json index 205120f6f0..2ae8edfa57 100644 --- a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json +++ b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Tool", - "summary": "", + "summary": "ImGui tools for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json index cff957c1f1..a7b9dab980 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Viewport display icons for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json index a2bc92c76d..0deeeef602 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Viewport Display Information for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/CommonFeatures/gem.json b/Gems/AtomLyIntegration/CommonFeatures/gem.json index a06f607fab..b6290679b9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/gem.json +++ b/Gems/AtomLyIntegration/CommonFeatures/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "Common features for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json index 8bea93da91..3847432cf7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json +++ b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "EmotionFX for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/AtomLyIntegration/ImguiAtom/gem.json b/Gems/AtomLyIntegration/ImguiAtom/gem.json index 4c65d80e33..70ff1c0414 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/gem.json +++ b/Gems/AtomLyIntegration/ImguiAtom/gem.json @@ -6,7 +6,7 @@ "origin": "Open 3D Engine - o3de.org", "origin_url": "https://github.com/o3de/o3de", "type": "Code", - "summary": "", + "summary": "ImGui support for Atom", "canonical_tags": [ "Gem" ], diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index 819592e018..d945db1665 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -104,7 +104,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAME FastNoise.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem FILES_CMAKE - fastnoise_tests_files.cmake + fastnoise_editor_tests_files.cmake COMPILE_DEFINITIONS PUBLIC FASTNOISE_EDITOR @@ -120,23 +120,31 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME Gem::FastNoise.Editor.Tests ) - else() - ly_add_target( - NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} - NAMESPACE Gem - FILES_CMAKE - fastnoise_tests_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Tests - BUILD_DEPENDENCIES - PRIVATE - AZ::AzTest - Gem::FastNoise.Static - Gem::LmbrCentral - ) - ly_add_googletest( - NAME Gem::FastNoise.Tests - ) endif() + + ly_add_target( + NAME FastNoise.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + fastnoise_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + Gem::FastNoise.Static + Gem::GradientSignal + Gem::GradientSignal.Tests.Static + Gem::LmbrCentral + ) + ly_add_googletest( + NAME Gem::FastNoise.Tests + ) + + ly_add_googlebenchmark( + NAME Gem::FastNoise.Benchmarks + TARGET Gem::FastNoise.Tests + ) + endif() diff --git a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp index 4cea2efcc8..ceeafc3af6 100644 --- a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp +++ b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.cpp @@ -54,6 +54,21 @@ namespace FastNoiseGem return AZ::Edit::PropertyVisibility::Hide; } + bool FastNoiseGradientConfig::operator==(const FastNoiseGradientConfig& rhs) const + { + return (m_cellularDistanceFunction == rhs.m_cellularDistanceFunction) + && (m_cellularJitter == rhs.m_cellularJitter) + && (m_cellularReturnType == rhs.m_cellularReturnType) + && (m_fractalType == rhs.m_fractalType) + && (m_frequency == rhs.m_frequency) + && (m_gain == rhs.m_gain) + && (m_interp == rhs.m_interp) + && (m_lacunarity == rhs.m_lacunarity) + && (m_noiseType == rhs.m_noiseType) + && (m_octaves == rhs.m_octaves) + && (m_seed == rhs.m_seed); + } + void FastNoiseGradientConfig::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) @@ -306,7 +321,7 @@ namespace FastNoiseGem float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const { - AZ::Vector3 uvw = sampleParams.m_position; + AZ::Vector3 uvw; bool wasPointRejected = false; { @@ -314,13 +329,34 @@ namespace FastNoiseGem m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected); } - if (!wasPointRejected) + // Generator returns a range between [-1, 1], map that to [0, 1] + return wasPointRejected ? + 0.0f : + AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f); + } + + void FastNoiseGradientComponent::GetValues(AZStd::span positions, AZStd::span outValues) const + { + if (positions.size() != outValues.size()) { - // Generator returns a range between [-1, 1], map that to [0, 1] - return AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f); + AZ_Assert(false, "input and output lists are different sizes (%zu vs %zu).", positions.size(), outValues.size()); + return; } - return 0.0f; + AZStd::shared_lock lock(m_transformMutex); + AZ::Vector3 uvw; + + for (size_t index = 0; index < positions.size(); index++) + { + bool wasPointRejected = false; + + m_gradientTransform.TransformPositionToUVW(positions[index], uvw, wasPointRejected); + + // Generator returns a range between [-1, 1], map that to [0, 1] + outValues[index] = wasPointRejected ? + 0.0f : + AZ::GetClamp((m_generator.GetNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ()) + 1.0f) / 2.0f, 0.0f, 1.0f); + } } template diff --git a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h index dd19049ee6..29c42bfe1b 100644 --- a/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h +++ b/Gems/FastNoise/Code/Source/FastNoiseGradientComponent.h @@ -47,6 +47,8 @@ namespace FastNoiseGem AZ::u32 GetFrequencyParameterVisbility() const; AZ::u32 GetInterpParameterVisibility() const; + bool operator==(const FastNoiseGradientConfig& rhs) const; + int m_seed = 1; float m_frequency = 1.f; FastNoise::Interp m_interp = FastNoise::Interp::Quintic; @@ -90,6 +92,7 @@ namespace FastNoiseGem // GradientRequestBus overrides... float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override; + void GetValues(AZStd::span positions, AZStd::span outValues) const override; protected: FastNoiseGradientConfig m_configuration; diff --git a/Gems/FastNoise/Code/Tests/FastNoiseBenchmarks.cpp b/Gems/FastNoise/Code/Tests/FastNoiseBenchmarks.cpp new file mode 100644 index 0000000000..1e438db112 --- /dev/null +++ b/Gems/FastNoise/Code/Tests/FastNoiseBenchmarks.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#ifdef HAVE_BENCHMARK + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace UnitTest +{ + class FastNoiseGetValues + : public ::benchmark::Fixture + { + public: + void RunGetValueOrGetValuesBenchmark(benchmark::State& state, FastNoise::NoiseType noiseType) + { + AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity"); + ASSERT_TRUE(noiseEntity != nullptr); + noiseEntity->CreateComponent(); + noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId); + noiseEntity->CreateComponent(); + + // Set up a FastNoise component with the requested noise type + FastNoiseGem::FastNoiseGradientConfig cfg; + cfg.m_frequency = 0.01f; + cfg.m_noiseType = noiseType; + noiseEntity->CreateComponent(cfg); + + noiseEntity->Init(); + noiseEntity->Activate(); + + UnitTest::GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, noiseEntity->GetId()); + } + + }; + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Value)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Value); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::ValueFractal); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Perlin); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::PerlinFractal); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Simplex); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::SimplexFractal); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cellular); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::WhiteNoise); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::Cubic); + } + + BENCHMARK_DEFINE_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal)(benchmark::State& state) + { + RunGetValueOrGetValuesBenchmark(state, FastNoise::NoiseType::CubicFractal); + } + + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Value); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_ValueFractal); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Perlin); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_PerlinFractal); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Simplex); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_SimplexFractal); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cellular); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_WhiteNoise); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_Cubic); + GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(FastNoiseGetValues, BM_FastNoiseGradient_CubicFractal); + +#endif +} + + + diff --git a/Gems/FastNoise/Code/Tests/FastNoiseEditorTest.cpp b/Gems/FastNoise/Code/Tests/FastNoiseEditorTest.cpp new file mode 100644 index 0000000000..e30c6c01e0 --- /dev/null +++ b/Gems/FastNoise/Code/Tests/FastNoiseEditorTest.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include +#include +#include + + +class FastNoiseEditorTestApp : public ::testing::Test +{ +}; + +TEST_F(FastNoiseEditorTestApp, FastNoise_EditorCreateGameEntity) +{ + AZStd::unique_ptr noiseEntity(aznew AZ::Entity("editor_noise_entity")); + ASSERT_TRUE(noiseEntity != nullptr); + + FastNoiseGem::EditorFastNoiseGradientComponent editor; + auto* editorBase = static_cast(&editor); + editorBase->BuildGameEntity(noiseEntity.get()); + + // the new game entity's FastNoise component should look like the default one + FastNoiseGem::FastNoiseGradientConfig defaultConfig; + FastNoiseGem::FastNoiseGradientConfig gameComponentConfig; + + FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent(); + ASSERT_TRUE(noiseComp != nullptr); + + // Change a value in the gameComponentConfig just to verify that it got overwritten instead of simply matching the default. + gameComponentConfig.m_seed++; + noiseComp->WriteOutConfig(&gameComponentConfig); + ASSERT_EQ(defaultConfig, gameComponentConfig); +} + +// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems. +AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment); diff --git a/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp b/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp index f0d5a9d1bd..1ac5e8ddca 100644 --- a/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp +++ b/Gems/FastNoise/Code/Tests/FastNoiseTest.cpp @@ -10,199 +10,61 @@ #include #include -#include -#include -#include #include +#include #include -#include -#include +#include #include -#include +#include +#include +#include #include #include #include +#include +#include -class MockGradientTransformComponent - : public AZ::Component - , private GradientSignal::GradientTransformRequestBus::Handler - , private GradientSignal::GradientTransformModifierRequestBus::Handler +class FastNoiseTest : public ::testing::Test { -public: - AZ_COMPONENT(MockGradientTransformComponent, "{464CF47B-7E10-4E1B-BD06-79BD2AC91399}"); - - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) - { - services.push_back(AZ_CRC("GradientTransformService", 0x8c8c5ecc)); - } - static void Reflect([[maybe_unused]] AZ::ReflectContext* context) {} - - MockGradientTransformComponent() = default; - ~MockGradientTransformComponent() = default; - - // AZ::Component interface - void Activate() override {} - void Deactivate() override {} - - //////////////////////////////////////////////////////////////////////////// - //// GradientTransformRequestBus - const GradientSignal::GradientTransform& GetGradientTransform() const override - { - return m_gradientTransform; - } - - ////////////////////////////////////////////////////////////////////////// - // GradientTransformModifierRequestBus - bool GetAllowReference() const override { return false; } - void SetAllowReference([[maybe_unused]] bool value) override {} - - AZ::EntityId GetShapeReference() const override { return AZ::EntityId(); } - void SetShapeReference([[maybe_unused]] AZ::EntityId shapeReference) override {} - - bool GetOverrideBounds() const override { return false; } - void SetOverrideBounds([[maybe_unused]] bool value) override {} - - AZ::Vector3 GetBounds() const override { return AZ::Vector3(); } - void SetBounds([[maybe_unused]] AZ::Vector3 bounds) override {} - - GradientSignal::TransformType GetTransformType() const override { return static_cast(0); } - void SetTransformType([[maybe_unused]] GradientSignal::TransformType type) override {} - - bool GetOverrideTranslate() const override { return false; } - void SetOverrideTranslate([[maybe_unused]] bool value) override {} - - AZ::Vector3 GetTranslate() const override { return AZ::Vector3(); } - void SetTranslate([[maybe_unused]] AZ::Vector3 translate) override {} - - bool GetOverrideRotate() const override { return false; } - void SetOverrideRotate([[maybe_unused]] bool value) override {} - - AZ::Vector3 GetRotate() const override { return AZ::Vector3(); } - void SetRotate([[maybe_unused]] AZ::Vector3 rotate) override {} - - bool GetOverrideScale() const override { return false; } - void SetOverrideScale([[maybe_unused]] bool value) override {} - - AZ::Vector3 GetScale() const override { return AZ::Vector3(); } - void SetScale([[maybe_unused]] AZ::Vector3 scale) override {} - - float GetFrequencyZoom() const override { return false; } - void SetFrequencyZoom([[maybe_unused]] float frequencyZoom) override {} - - GradientSignal::WrappingType GetWrappingType() const override { return static_cast(0); } - void SetWrappingType([[maybe_unused]] GradientSignal::WrappingType type) override {} - - bool GetIs3D() const override { return false; } - void SetIs3D([[maybe_unused]] bool value) override {} - - bool GetAdvancedMode() const override { return false; } - void SetAdvancedMode([[maybe_unused]] bool value) override {} - - GradientSignal::GradientTransform m_gradientTransform; }; -TEST(FastNoiseTest, ComponentsWithComponentApplication) -{ - AZ::ComponentApplication::Descriptor appDesc; - appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024; - appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL; - appDesc.m_stackRecordLevels = 20; - - AZ::ComponentApplication app; - AZ::Entity* systemEntity = app.Create(appDesc); - ASSERT_TRUE(systemEntity != nullptr); - app.RegisterComponentDescriptor(FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor()); - systemEntity->CreateComponent(); - - systemEntity->Init(); - systemEntity->Activate(); - - AZ::Entity* noiseEntity = aznew AZ::Entity("fastnoise_entity"); - noiseEntity->CreateComponent(); - app.AddEntity(noiseEntity); - - app.Destroy(); - ASSERT_TRUE(true); -} - -class FastNoiseTestApp - : public ::testing::Test -{ -public: - FastNoiseTestApp() - : m_application() - , m_systemEntity(nullptr) - { - } - - void SetUp() override - { - AZ::ComponentApplication::Descriptor appDesc; - appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024; - appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_FULL; - appDesc.m_stackRecordLevels = 20; - - AZ::ComponentApplication::StartupParameters appStartup; - appStartup.m_createStaticModulesCallback = - [](AZStd::vector& modules) - { - modules.emplace_back(new FastNoiseGem::FastNoiseModule); - }; - - m_systemEntity = m_application.Create(appDesc, appStartup); - m_application.RegisterComponentDescriptor(MockGradientTransformComponent::CreateDescriptor()); - m_systemEntity->Init(); - m_systemEntity->Activate(); - } - - void TearDown() override - { - m_application.Destroy(); - } - - AZ::ComponentApplication m_application; - AZ::Entity* m_systemEntity; -}; - -////////////////////////////////////////////////////////////////////////// -// testing class to inspect protected data members in the FastNoiseGradientComponent -struct FastNoiseGradientComponentTester : public FastNoiseGem::FastNoiseGradientComponent -{ - const FastNoiseGem::FastNoiseGradientConfig& GetConfig() const { return m_configuration; } - - void AssertTrue(const FastNoiseGem::FastNoiseGradientConfig& cfg) - { - ASSERT_TRUE(m_configuration.m_cellularDistanceFunction == cfg.m_cellularDistanceFunction); - ASSERT_TRUE(m_configuration.m_cellularJitter == cfg.m_cellularJitter); - ASSERT_TRUE(m_configuration.m_cellularReturnType == cfg.m_cellularReturnType); - ASSERT_TRUE(m_configuration.m_fractalType == cfg.m_fractalType); - ASSERT_TRUE(m_configuration.m_frequency == cfg.m_frequency); - ASSERT_TRUE(m_configuration.m_gain == cfg.m_gain); - ASSERT_TRUE(m_configuration.m_interp == cfg.m_interp); - ASSERT_TRUE(m_configuration.m_lacunarity == cfg.m_lacunarity); - ASSERT_TRUE(m_configuration.m_noiseType == cfg.m_noiseType); - ASSERT_TRUE(m_configuration.m_octaves == cfg.m_octaves); - ASSERT_TRUE(m_configuration.m_seed == cfg.m_seed); - } -}; - -TEST_F(FastNoiseTestApp, FastNoise_Component) +TEST_F(FastNoiseTest, FastNoise_ComponentCreatesSuccessfully) { AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity"); ASSERT_TRUE(noiseEntity != nullptr); noiseEntity->CreateComponent(); - m_application.AddEntity(noiseEntity); FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent(); ASSERT_TRUE(noiseComp != nullptr); } -TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus) +TEST_F(FastNoiseTest, FastNoise_ComponentMatchesConfiguration) { AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity"); ASSERT_TRUE(noiseEntity != nullptr); + + FastNoiseGem::FastNoiseGradientConfig cfg; + FastNoiseGem::FastNoiseGradientConfig componentConfig; + + noiseEntity->CreateComponent(); + noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId); + noiseEntity->CreateComponent(); + noiseEntity->CreateComponent(cfg); + + FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent(); + ASSERT_TRUE(noiseComp != nullptr); + noiseComp->WriteOutConfig(&componentConfig); + ASSERT_EQ(cfg, componentConfig); +} + +TEST_F(FastNoiseTest, FastNoise_ComponentEbusWorksSuccessfully) +{ + AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity"); + ASSERT_TRUE(noiseEntity != nullptr); + noiseEntity->CreateComponent(); + noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId); + noiseEntity->CreateComponent(); noiseEntity->CreateComponent(); - noiseEntity->CreateComponent(); noiseEntity->Init(); noiseEntity->Activate(); @@ -210,51 +72,39 @@ TEST_F(FastNoiseTestApp, FastNoise_ComponentEbus) GradientSignal::GradientSampleParams params; float sample = -1.0f; - GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(), &GradientSignal::GradientRequestBus::Events::GetValue, params); + GradientSignal::GradientRequestBus::EventResult(sample, noiseEntity->GetId(), + &GradientSignal::GradientRequestBus::Events::GetValue, params); ASSERT_TRUE(sample >= 0.0f); ASSERT_TRUE(sample <= 1.0f); } -TEST_F(FastNoiseTestApp, FastNoise_ComponentMatchesConfiguration) +TEST_F(FastNoiseTest, FastNoise_VerifyGetValueAndGetValuesMatch) { + const float shapeHalfBounds = 128.0f; + AZ::Entity* noiseEntity = aznew AZ::Entity("noise_entity"); ASSERT_TRUE(noiseEntity != nullptr); + noiseEntity->CreateComponent(); + noiseEntity->CreateComponent(); - AZ::SimpleLcgRandom rand(AZStd::GetTimeNowMicroSecond()); + // Create a Box Shape to map our gradient into + LmbrCentral::BoxShapeConfig boxConfig(AZ::Vector3(shapeHalfBounds * 2.0f)); + auto boxComponent = noiseEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId); + boxComponent->SetConfiguration(boxConfig); + // Create a Fast Noise component with an adjusted frequency. (The defaults of Perlin noise with frequency=1.0 would cause us + // to always get back the same noise value) FastNoiseGem::FastNoiseGradientConfig cfg; - + cfg.m_frequency = 0.01f; noiseEntity->CreateComponent(cfg); - noiseEntity->CreateComponent(); - m_application.AddEntity(noiseEntity); + noiseEntity->Init(); + noiseEntity->Activate(); - FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent(); - ASSERT_TRUE(noiseComp != nullptr); - reinterpret_cast(noiseComp)->AssertTrue(cfg); + // Create a gradient sampler and run through a series of points to see if they match expectations. + UnitTest::GradientSignalTestHelpers::CompareGetValueAndGetValues(noiseEntity->GetId(), shapeHalfBounds); } -#if FASTNOISE_EDITOR -#include - -TEST_F(FastNoiseTestApp, FastNoise_EditorCreateGameEntity) -{ - AZStd::unique_ptr noiseEntity(aznew AZ::Entity("editor_noise_entity")); - ASSERT_TRUE(noiseEntity != nullptr); - - FastNoiseGem::EditorFastNoiseGradientComponent editor; - auto* editorBase = static_cast(&editor); - editorBase->BuildGameEntity(noiseEntity.get()); - - // the new game entity's ocean component should look like the default one - FastNoiseGem::FastNoiseGradientConfig cfg; - - FastNoiseGem::FastNoiseGradientComponent* noiseComp = noiseEntity->FindComponent(); - ASSERT_TRUE(noiseComp != nullptr); - reinterpret_cast(noiseComp)->AssertTrue(cfg); -} - -#endif - -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +// This uses custom test / benchmark hooks so that we can load LmbrCentral and GradientSignal Gems. +AZ_UNIT_TEST_HOOK(new UnitTest::FastNoiseTestEnvironment, UnitTest::FastNoiseBenchmarkEnvironment); diff --git a/Gems/FastNoise/Code/Tests/FastNoiseTest.h b/Gems/FastNoise/Code/Tests/FastNoiseTest.h new file mode 100644 index 0000000000..71b10cfc68 --- /dev/null +++ b/Gems/FastNoise/Code/Tests/FastNoiseTest.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +namespace UnitTest +{ + // The FastNoise unit tests need to use the GemTestEnvironment to load the GradientSignal and LmbrCentral Gems so that + // GradientTransform components can be used in the unit tests and benchmarks. + class FastNoiseTestEnvironment + : public AZ::Test::GemTestEnvironment + { + public: + void AddGemsAndComponents() override + { + AddDynamicModulePaths({ "GradientSignal" }); + AddDynamicModulePaths({ "LmbrCentral" }); + + AddComponentDescriptors({ + AzFramework::TransformComponent::CreateDescriptor(), + FastNoiseGem::FastNoiseSystemComponent::CreateDescriptor(), + FastNoiseGem::FastNoiseGradientComponent::CreateDescriptor() + }); + + AddRequiredComponents({ FastNoiseGem::FastNoiseSystemComponent::TYPEINFO_Uuid() }); + } + }; + +#ifdef HAVE_BENCHMARK + //! The Benchmark environment is used for one time setup and tear down of shared resources + class FastNoiseBenchmarkEnvironment + : public AZ::Test::BenchmarkEnvironmentBase + , public FastNoiseTestEnvironment + + { + protected: + void SetUpBenchmark() override + { + SetupEnvironment(); + } + + void TearDownBenchmark() override + { + TeardownEnvironment(); + } + }; +#endif + + +} // namespace UnitTest + diff --git a/Gems/FastNoise/Code/fastnoise_editor_tests_files.cmake b/Gems/FastNoise/Code/fastnoise_editor_tests_files.cmake new file mode 100644 index 0000000000..685e2fb647 --- /dev/null +++ b/Gems/FastNoise/Code/fastnoise_editor_tests_files.cmake @@ -0,0 +1,13 @@ +# +# 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/FastNoiseEditorTest.cpp + Source/FastNoiseModule.h + Source/FastNoiseModule.cpp +) diff --git a/Gems/FastNoise/Code/fastnoise_tests_files.cmake b/Gems/FastNoise/Code/fastnoise_tests_files.cmake index 08386940f2..4669b0d446 100644 --- a/Gems/FastNoise/Code/fastnoise_tests_files.cmake +++ b/Gems/FastNoise/Code/fastnoise_tests_files.cmake @@ -7,6 +7,7 @@ # set(FILES + Tests/FastNoiseBenchmarks.cpp Tests/FastNoiseTest.cpp Source/FastNoiseModule.h Source/FastNoiseModule.cpp diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp index bd4ccf5205..6ffb4a31c4 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalBenchmarks.cpp @@ -9,6 +9,7 @@ #ifdef HAVE_BENCHMARK #include +#include #include #include @@ -21,220 +22,42 @@ namespace UnitTest class GradientGetValues : public GradientSignalBenchmarkFixture { public: - // We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases - // to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark - // function for each test case for each gradient. - enum GetValuePermutation : int64_t - { - EBUS_GET_VALUE, - EBUS_GET_VALUES, - SAMPLER_GET_VALUE, - SAMPLER_GET_VALUES, - }; - // Create an arbitrary size shape for creating our gradients for benchmark runs. const float TestShapeHalfBounds = 128.0f; - - void FillQueryPositions(AZStd::vector& positions, float height, float width) - { - 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); - } - } - } - - void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) - { - AZ_PROFILE_FUNCTION(Entity); - - GradientSignal::GradientSampleParams params; - - // Get the height and width ranges for querying from our benchmark parameters - const float height = aznumeric_cast(queryRange); - const float width = aznumeric_cast(queryRange); - - // Call GetValue() on the EBus 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, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); - benchmark::DoNotOptimize(value); - } - } - } - } - - void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) - { - AZ_PROFILE_FUNCTION(Entity); - - // Get the height and width ranges for querying from our benchmark parameters - float height = aznumeric_cast(queryRange); - float width = aznumeric_cast(queryRange); - int64_t totalQueryPoints = queryRange * queryRange; - - // Call GetValues() for every height and width in our ranges. - for (auto _ : state) - { - // Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create - // each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable. - AZStd::vector positions(totalQueryPoints); - FillQueryPositions(positions, height, width); - - // Query and get the results. - AZStd::vector results(totalQueryPoints); - GradientSignal::GradientRequestBus::Event( - gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results); - } - } - - void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) - { - AZ_PROFILE_FUNCTION(Entity); - - // Create a gradient sampler to use for querying our gradient. - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = gradientId; - - // Get the height and width ranges for querying from our benchmark parameters - const float height = aznumeric_cast(queryRange); - const float width = aznumeric_cast(queryRange); - - // Call GetValue() through the GradientSampler for every height and width in our ranges. - for (auto _ : state) - { - for (float y = 0.0f; y < height; y += 1.0f) - { - for (float x = 0.0f; x < width; x += 1.0f) - { - GradientSignal::GradientSampleParams params; - params.m_position = AZ::Vector3(x, y, 0.0f); - float value = gradientSampler.GetValue(params); - benchmark::DoNotOptimize(value); - } - } - } - } - - void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) - { - AZ_PROFILE_FUNCTION(Entity); - - // Create a gradient sampler to use for querying our gradient. - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = gradientId; - - // Get the height and width ranges for querying from our benchmark parameters - const float height = aznumeric_cast(queryRange); - const float width = aznumeric_cast(queryRange); - const int64_t totalQueryPoints = queryRange * queryRange; - - // Call GetValues() through the GradientSampler for every height and width in our ranges. - for (auto _ : state) - { - // Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create - // each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable. - AZStd::vector positions(totalQueryPoints); - FillQueryPositions(positions, height, width); - - // Query and get the results. - AZStd::vector results(totalQueryPoints); - gradientSampler.GetValues(positions, results); - } - } - - void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId) - { - switch (state.range(0)) - { - case GetValuePermutation::EBUS_GET_VALUE: - RunEBusGetValueBenchmark(state, gradientId, state.range(1)); - break; - case GetValuePermutation::EBUS_GET_VALUES: - RunEBusGetValuesBenchmark(state, gradientId, state.range(1)); - break; - case GetValuePermutation::SAMPLER_GET_VALUE: - RunSamplerGetValueBenchmark(state, gradientId, state.range(1)); - break; - case GetValuePermutation::SAMPLER_GET_VALUES: - RunSamplerGetValuesBenchmark(state, gradientId, state.range(1)); - break; - default: - AZ_Assert(false, "Benchmark permutation type not supported."); - } - } }; -// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by -// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results. -#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \ - BENCHMARK_REGISTER_F(Fixture, Func) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \ - ->ArgNames({ "EbusGetValue", "size" }) \ - ->Unit(::benchmark::kMillisecond); \ - BENCHMARK_REGISTER_F(Fixture, Func) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \ - ->Args({ GradientGetValues::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \ - ->ArgNames({ "EbusGetValues", "size" }) \ - ->Unit(::benchmark::kMillisecond); \ - BENCHMARK_REGISTER_F(Fixture, Func) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \ - ->ArgNames({ "SamplerGetValue", "size" }) \ - ->Unit(::benchmark::kMillisecond); \ - BENCHMARK_REGISTER_F(Fixture, Func) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \ - ->Args({ GradientGetValues::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \ - ->ArgNames({ "SamplerGetValues", "size" }) \ - ->Unit(::benchmark::kMillisecond); - // -------------------------------------------------------------------------------------- // Base Gradients BENCHMARK_DEFINE_F(GradientGetValues, BM_ConstantGradient)(benchmark::State& state) { auto entity = BuildTestConstantGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_ImageGradient)(benchmark::State& state) { auto entity = BuildTestImageGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_PerlinGradient)(benchmark::State& state) { auto entity = BuildTestPerlinGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_RandomGradient)(benchmark::State& state) { auto entity = BuildTestRandomGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_ShapeAreaFalloffGradient)(benchmark::State& state) { auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_ConstantGradient); @@ -250,21 +73,21 @@ namespace UnitTest { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_InvertGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_LevelsGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_MixedGradient)(benchmark::State& state) @@ -272,35 +95,35 @@ namespace UnitTest auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds); auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_PosterizeGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_ReferenceGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_SmoothStepGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_ThresholdGradient)(benchmark::State& state) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId()); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_DitherGradient); @@ -321,7 +144,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceMaskGradient)(benchmark::State& state) @@ -330,7 +153,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } BENCHMARK_DEFINE_F(GradientGetValues, BM_SurfaceSlopeGradient)(benchmark::State& state) @@ -339,7 +162,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds); - RunGetValueOrGetValuesBenchmark(state, entity->GetId()); + GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(state, entity->GetId()); } GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(GradientGetValues, BM_SurfaceAltitudeGradient); diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp index 6c4ebcc4c0..f0ad53ee64 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalGetValuesTests.cpp @@ -8,6 +8,7 @@ #include +#include #include namespace UnitTest @@ -18,79 +19,36 @@ namespace UnitTest // Create an arbitrary size shape for comparing values within. It should be large enough that we detect any value anomalies // but small enough that the tests run quickly. const float TestShapeHalfBounds = 128.0f; - - void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId) - { - // Create a gradient sampler and run through a series of points to see if they match expectations. - - const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds)); - const AZ::Vector2 stepSize(1.0f, 1.0f); - - GradientSignal::GradientSampler gradientSampler; - gradientSampler.m_gradientId = gradientEntityId; - - const size_t numSamplesX = aznumeric_cast(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX())); - const size_t numSamplesY = aznumeric_cast(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY())); - - // Build up the list of positions to query. - AZStd::vector positions(numSamplesX * numSamplesY); - size_t index = 0; - for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++) - { - float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex); - for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++) - { - float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex); - positions[index++] = AZ::Vector3(x, y, 0.0f); - } - } - - // Get the results from GetValues - AZStd::vector results(numSamplesX * numSamplesY); - gradientSampler.GetValues(positions, results); - - // For each position, call GetValue and verify that the values match. - for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++) - { - GradientSignal::GradientSampleParams params; - params.m_position = positions[positionIndex]; - float value = gradientSampler.GetValue(params); - - // We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no - // reason to keep running and printing failures for every value. - ASSERT_NEAR(value, results[positionIndex], 0.000001f); - } - } }; TEST_F(GradientSignalGetValuesTestsFixture, ImageGradientComponent_VerifyGetValueAndGetValuesMatch) { auto entity = BuildTestImageGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, PerlinGradientComponent_VerifyGetValueAndGetValuesMatch) { auto entity = BuildTestPerlinGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, RandomGradientComponent_VerifyGetValueAndGetValuesMatch) { auto entity = BuildTestRandomGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, ConstantGradientComponent_VerifyGetValueAndGetValuesMatch) { auto entity = BuildTestConstantGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, ShapeAreaFalloffGradientComponent_VerifyGetValueAndGetValuesMatch) { auto entity = BuildTestShapeAreaFalloffGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, DitherGradientComponent_VerifyGetValueAndGetValuesMatch) @@ -98,21 +56,21 @@ namespace UnitTest auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestDitherGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, InvertGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestInvertGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, LevelsGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestLevelsGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, MixedGradientComponent_VerifyGetValueAndGetValuesMatch) @@ -120,35 +78,35 @@ namespace UnitTest auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto mixedEntity = BuildTestConstantGradient(TestShapeHalfBounds); auto entity = BuildTestMixedGradient(TestShapeHalfBounds, baseEntity->GetId(), mixedEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, PosterizeGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestPosterizeGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, ReferenceGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestReferenceGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, SmoothStepGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestSmoothStepGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, ThresholdGradientComponent_VerifyGetValueAndGetValuesMatch) { auto baseEntity = BuildTestRandomGradient(TestShapeHalfBounds); auto entity = BuildTestThresholdGradient(TestShapeHalfBounds, baseEntity->GetId()); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, SurfaceAltitudeGradientComponent_VerifyGetValueAndGetValuesMatch) @@ -157,7 +115,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceAltitudeGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, SurfaceMaskGradientComponent_VerifyGetValueAndGetValuesMatch) @@ -166,7 +124,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceMaskGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } TEST_F(GradientSignalGetValuesTestsFixture, SurfaceSlopeGradientComponent_VerifyGetValueAndGetValuesMatch) @@ -175,7 +133,7 @@ namespace UnitTest CreateMockSurfaceDataSystem(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TestShapeHalfBounds), AZ::Vector3(TestShapeHalfBounds))); auto entity = BuildTestSurfaceSlopeGradient(TestShapeHalfBounds); - CompareGetValueAndGetValues(entity->GetId()); + GradientSignalTestHelpers::CompareGetValueAndGetValues(entity->GetId(), TestShapeHalfBounds); } } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.cpp new file mode 100644 index 0000000000..46cc3475e8 --- /dev/null +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include + +namespace UnitTest +{ + void GradientSignalTestHelpers::CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds) + { + // Create a gradient sampler and run through a series of points to see if they match expectations. + + const AZ::Aabb queryRegion = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-shapeHalfBounds), AZ::Vector3(shapeHalfBounds)); + const AZ::Vector2 stepSize(1.0f, 1.0f); + + GradientSignal::GradientSampler gradientSampler; + gradientSampler.m_gradientId = gradientEntityId; + + const size_t numSamplesX = aznumeric_cast(ceil(queryRegion.GetExtents().GetX() / stepSize.GetX())); + const size_t numSamplesY = aznumeric_cast(ceil(queryRegion.GetExtents().GetY() / stepSize.GetY())); + + // Build up the list of positions to query. + AZStd::vector positions(numSamplesX * numSamplesY); + size_t index = 0; + for (size_t yIndex = 0; yIndex < numSamplesY; yIndex++) + { + float y = queryRegion.GetMin().GetY() + (stepSize.GetY() * yIndex); + for (size_t xIndex = 0; xIndex < numSamplesX; xIndex++) + { + float x = queryRegion.GetMin().GetX() + (stepSize.GetX() * xIndex); + positions[index++] = AZ::Vector3(x, y, 0.0f); + } + } + + // Get the results from GetValues + AZStd::vector results(numSamplesX * numSamplesY); + gradientSampler.GetValues(positions, results); + + // For each position, call GetValue and verify that the values match. + for (size_t positionIndex = 0; positionIndex < positions.size(); positionIndex++) + { + GradientSignal::GradientSampleParams params; + params.m_position = positions[positionIndex]; + float value = gradientSampler.GetValue(params); + + // We use ASSERT_NEAR instead of EXPECT_NEAR because if one value doesn't match, they probably all won't, so there's no + // reason to keep running and printing failures for every value. + ASSERT_NEAR(value, results[positionIndex], 0.000001f); + } + } + +#ifdef HAVE_BENCHMARK + + void GradientSignalTestHelpers::FillQueryPositions(AZStd::vector& positions, float height, float width) + { + 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); + } + } + } + + void GradientSignalTestHelpers::RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) + { + AZ_PROFILE_FUNCTION(Entity); + + GradientSignal::GradientSampleParams params; + + // Get the height and width ranges for querying from our benchmark parameters + const float height = aznumeric_cast(queryRange); + const float width = aznumeric_cast(queryRange); + + // Call GetValue() on the EBus 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, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); + benchmark::DoNotOptimize(value); + } + } + } + } + + void GradientSignalTestHelpers::RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) + { + AZ_PROFILE_FUNCTION(Entity); + + // Get the height and width ranges for querying from our benchmark parameters + float height = aznumeric_cast(queryRange); + float width = aznumeric_cast(queryRange); + int64_t totalQueryPoints = queryRange * queryRange; + + // Call GetValues() for every height and width in our ranges. + for (auto _ : state) + { + // Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create + // each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable. + AZStd::vector positions(totalQueryPoints); + FillQueryPositions(positions, height, width); + + // Query and get the results. + AZStd::vector results(totalQueryPoints); + GradientSignal::GradientRequestBus::Event( + gradientId, &GradientSignal::GradientRequestBus::Events::GetValues, positions, results); + } + } + + void GradientSignalTestHelpers::RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) + { + AZ_PROFILE_FUNCTION(Entity); + + // Create a gradient sampler to use for querying our gradient. + GradientSignal::GradientSampler gradientSampler; + gradientSampler.m_gradientId = gradientId; + + // Get the height and width ranges for querying from our benchmark parameters + const float height = aznumeric_cast(queryRange); + const float width = aznumeric_cast(queryRange); + + // Call GetValue() through the GradientSampler for every height and width in our ranges. + for (auto _ : state) + { + for (float y = 0.0f; y < height; y += 1.0f) + { + for (float x = 0.0f; x < width; x += 1.0f) + { + GradientSignal::GradientSampleParams params; + params.m_position = AZ::Vector3(x, y, 0.0f); + float value = gradientSampler.GetValue(params); + benchmark::DoNotOptimize(value); + } + } + } + } + + void GradientSignalTestHelpers::RunSamplerGetValuesBenchmark( + benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange) + { + AZ_PROFILE_FUNCTION(Entity); + + // Create a gradient sampler to use for querying our gradient. + GradientSignal::GradientSampler gradientSampler; + gradientSampler.m_gradientId = gradientId; + + // Get the height and width ranges for querying from our benchmark parameters + const float height = aznumeric_cast(queryRange); + const float width = aznumeric_cast(queryRange); + const int64_t totalQueryPoints = queryRange * queryRange; + + // Call GetValues() through the GradientSampler for every height and width in our ranges. + for (auto _ : state) + { + // Set up our vector of query positions. This is done inside the benchmark timing since we're counting the work to create + // each query position in the single GetValue() call benchmarks, and will make the timing more directly comparable. + AZStd::vector positions(totalQueryPoints); + FillQueryPositions(positions, height, width); + + // Query and get the results. + AZStd::vector results(totalQueryPoints); + gradientSampler.GetValues(positions, results); + } + } + + void GradientSignalTestHelpers::RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId) + { + switch (state.range(0)) + { + case GetValuePermutation::EBUS_GET_VALUE: + RunEBusGetValueBenchmark(state, gradientId, state.range(1)); + break; + case GetValuePermutation::EBUS_GET_VALUES: + RunEBusGetValuesBenchmark(state, gradientId, state.range(1)); + break; + case GetValuePermutation::SAMPLER_GET_VALUE: + RunSamplerGetValueBenchmark(state, gradientId, state.range(1)); + break; + case GetValuePermutation::SAMPLER_GET_VALUES: + RunSamplerGetValuesBenchmark(state, gradientId, state.range(1)); + break; + default: + AZ_Assert(false, "Benchmark permutation type not supported."); + } + } +#endif +} + + diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.h b/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.h new file mode 100644 index 0000000000..8a175939ee --- /dev/null +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestHelpers.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +namespace UnitTest +{ + class GradientSignalTestHelpers + { + public: + static void CompareGetValueAndGetValues(AZ::EntityId gradientEntityId, float shapeHalfBounds); + +#ifdef HAVE_BENCHMARK + // We use an enum to list out the different types of GetValue() benchmarks to run so that way we can condense our test cases + // to just take the value in as a benchmark argument and switch on it. Otherwise, we would need to write a different benchmark + // function for each test case for each gradient. + enum GetValuePermutation : int64_t + { + EBUS_GET_VALUE, + EBUS_GET_VALUES, + SAMPLER_GET_VALUE, + SAMPLER_GET_VALUES, + }; + + static void FillQueryPositions(AZStd::vector& positions, float height, float width); + + static void RunEBusGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange); + static void RunEBusGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange); + static void RunSamplerGetValueBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange); + static void RunSamplerGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId, int64_t queryRange); + static void RunGetValueOrGetValuesBenchmark(benchmark::State& state, const AZ::EntityId& gradientId); + +// Because there's no good way to label different enums in the output results (they just appear as integer values), we work around it by +// registering one set of benchmark runs for each enum value and use ArgNames() to give it a friendly name in the results. +#ifndef GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F +#define GRADIENT_SIGNAL_GET_VALUES_BENCHMARK_REGISTER_F(Fixture, Func) \ + BENCHMARK_REGISTER_F(Fixture, Func) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 1024 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 2048 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUE, 4096 }) \ + ->ArgNames({ "EbusGetValue", "size" }) \ + ->Unit(::benchmark::kMillisecond); \ + BENCHMARK_REGISTER_F(Fixture, Func) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 1024 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 2048 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::EBUS_GET_VALUES, 4096 }) \ + ->ArgNames({ "EbusGetValues", "size" }) \ + ->Unit(::benchmark::kMillisecond); \ + BENCHMARK_REGISTER_F(Fixture, Func) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 1024 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 2048 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUE, 4096 }) \ + ->ArgNames({ "SamplerGetValue", "size" }) \ + ->Unit(::benchmark::kMillisecond); \ + BENCHMARK_REGISTER_F(Fixture, Func) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 1024 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 2048 }) \ + ->Args({ GradientSignalTestHelpers::GetValuePermutation::SAMPLER_GET_VALUES, 4096 }) \ + ->ArgNames({ "SamplerGetValues", "size" }) \ + ->Unit(::benchmark::kMillisecond); +#endif + +#endif + }; + + +} diff --git a/Gems/GradientSignal/Code/gradientsignal_shared_tests_files.cmake b/Gems/GradientSignal/Code/gradientsignal_shared_tests_files.cmake index 7d867b0a33..98ab57b7b0 100644 --- a/Gems/GradientSignal/Code/gradientsignal_shared_tests_files.cmake +++ b/Gems/GradientSignal/Code/gradientsignal_shared_tests_files.cmake @@ -7,6 +7,8 @@ # set(FILES + Tests/GradientSignalTestHelpers.cpp + Tests/GradientSignalTestHelpers.h Tests/GradientSignalTestFixtures.cpp Tests/GradientSignalTestFixtures.h Tests/GradientSignalTestMocks.cpp