From b8bed115f0b5366405d1f3058c1e2107e36f0f1b Mon Sep 17 00:00:00 2001 From: Nemerle Date: Thu, 5 Aug 2021 16:37:43 +0200 Subject: [PATCH 01/18] Editor code: tidy up BOOLs,NULLs and overrides pt1. A few 'typedefs' replaced by 'using's This shouldn't have any functional changes at all, just c++17 modernization It's a part 1 of a split #2847 Signed-off-by: Nemerle --- Code/Editor/Animation/SkeletonHierarchy.cpp | 2 +- Code/Editor/Animation/SkeletonMapper.cpp | 8 +- .../Animation/SkeletonMapperOperator.cpp | 4 +- Code/Editor/AnimationContext.cpp.rej | 11 --- .../AzAssetBrowser/AzAssetBrowserWindow.cpp | 2 +- Code/Editor/Commands/CommandManager.cpp | 6 +- Code/Editor/Commands/CommandManager.h | 2 +- Code/Editor/Controls/BitmapToolTip.h | 2 +- Code/Editor/Controls/ColorGradientCtrl.cpp | 6 +- Code/Editor/Controls/ColorGradientCtrl.h | 2 +- Code/Editor/Controls/ConsoleSCB.cpp | 6 +- Code/Editor/Controls/HotTrackingTreeCtrl.cpp | 8 +- .../ReflectedPropertiesPanel.cpp | 2 +- .../ReflectedPropertyCtrl.cpp | 14 ++-- .../ReflectedPropertyItem.cpp | 8 +- .../ReflectedVarWrapper.cpp | 2 +- Code/Editor/Controls/SplineCtrl.cpp | 10 +-- Code/Editor/Controls/SplineCtrl.h | 2 +- Code/Editor/Controls/SplineCtrlEx.cpp | 76 +++++++++---------- Code/Editor/Controls/TimelineCtrl.cpp | 2 +- Code/Editor/Core/LevelEditorMenuHandler.cpp | 4 +- Code/Editor/Core/QtEditorApplication.cpp | 2 +- Code/Editor/Core/Tests/test_Main.cpp | 2 +- Code/Editor/Dialogs/ErrorsDlg.cpp | 2 +- Code/Editor/Dialogs/PythonScriptsDialog.cpp | 2 +- Code/Editor/Export/ExportManager.cpp | 22 +++--- Code/Editor/Export/OBJExporter.cpp | 2 +- Code/Editor/Geometry/TriMesh.cpp | 22 +++--- Code/Editor/Include/IAssetItem.h | 6 +- Code/Editor/Include/IFileUtil.h | 11 ++- 30 files changed, 123 insertions(+), 127 deletions(-) delete mode 100644 Code/Editor/AnimationContext.cpp.rej diff --git a/Code/Editor/Animation/SkeletonHierarchy.cpp b/Code/Editor/Animation/SkeletonHierarchy.cpp index 3015ff5e27..d1cc44b31d 100644 --- a/Code/Editor/Animation/SkeletonHierarchy.cpp +++ b/Code/Editor/Animation/SkeletonHierarchy.cpp @@ -63,7 +63,7 @@ int32 CHierarchy::FindNodeIndexByName(const char* name) const const CHierarchy::SNode* CHierarchy::FindNode(const char* name) const { int32 index = FindNodeIndexByName(name); - return index < 0 ? NULL : &m_nodes[index]; + return index < 0 ? nullptr : &m_nodes[index]; } void CHierarchy::CreateFrom(IDefaultSkeleton* pIDefaultSkeleton) diff --git a/Code/Editor/Animation/SkeletonMapper.cpp b/Code/Editor/Animation/SkeletonMapper.cpp index 3913801fc8..24f01f56ad 100644 --- a/Code/Editor/Animation/SkeletonMapper.cpp +++ b/Code/Editor/Animation/SkeletonMapper.cpp @@ -56,8 +56,8 @@ void CMapper::ClearLocations() uint32 count = uint32(m_nodes.size()); for (uint32 i = 0; i < count; ++i) { - m_nodes[i].position = NULL; - m_nodes[i].orientation = NULL; + m_nodes[i].position = nullptr; + m_nodes[i].orientation = nullptr; } m_locations.clear(); @@ -141,7 +141,7 @@ void CMapper::Map(QuatT* pResult) } CHierarchy::SNode* pParent = pNode->parent < 0 ? - NULL : m_hierarchy.GetNode(pNode->parent); + nullptr : m_hierarchy.GetNode(pNode->parent); if (pParent) { pResult[i].t = @@ -173,7 +173,7 @@ void CMapper::Map(QuatT* pResult) } CHierarchy::SNode* pParent = pNode->parent < 0 ? - NULL : m_hierarchy.GetNode(pNode->parent); + nullptr : m_hierarchy.GetNode(pNode->parent); if (!pParent) { pResult[i].q = absolutes[i]; diff --git a/Code/Editor/Animation/SkeletonMapperOperator.cpp b/Code/Editor/Animation/SkeletonMapperOperator.cpp index 7a69173bed..cc53957115 100644 --- a/Code/Editor/Animation/SkeletonMapperOperator.cpp +++ b/Code/Editor/Animation/SkeletonMapperOperator.cpp @@ -37,8 +37,8 @@ CMapperOperatorDesc::CMapperOperatorDesc(const char* name) CMapperOperator::CMapperOperator(const char* className, uint32 positionCount, uint32 orientationCount) { m_className = className; - m_position.resize(positionCount, NULL); - m_orientation.resize(orientationCount, NULL); + m_position.resize(positionCount, nullptr); + m_orientation.resize(orientationCount, nullptr); } CMapperOperator::~CMapperOperator() diff --git a/Code/Editor/AnimationContext.cpp.rej b/Code/Editor/AnimationContext.cpp.rej deleted file mode 100644 index 3ee0913c9d..0000000000 --- a/Code/Editor/AnimationContext.cpp.rej +++ /dev/null @@ -1,11 +0,0 @@ ---- Editor/AnimationContext.cpp -+++ Editor/AnimationContext.cpp -@@ -612,7 +612,7 @@ void CAnimationContext::UpdateAnimatedLights() - return; - - std::vector entityObjects; -- GetIEditor()->GetObjectManager()->FindObjectsOfType(entityObjects); -+ GetIEditor()->GetObjectManager()->FindObjectsOfType(&CEntityObject::staticMetaObject, entityObjects); - std::for_each(std::begin(entityObjects), std::end(entityObjects), - [this](CBaseObject *pBaseObject) - { diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp index f1047ae62b..c93ad087ce 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp @@ -42,7 +42,7 @@ public: AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); } - ~ListenerForShowAssetEditorEvent() + ~ListenerForShowAssetEditorEvent() override { AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); } diff --git a/Code/Editor/Commands/CommandManager.cpp b/Code/Editor/Commands/CommandManager.cpp index 90059ea195..0712e35e79 100644 --- a/Code/Editor/Commands/CommandManager.cpp +++ b/Code/Editor/Commands/CommandManager.cpp @@ -20,8 +20,8 @@ // AzToolsFramework #include -CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::s_pFirst = 0; -CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::s_pLast = 0; +CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::s_pFirst = nullptr; +CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::s_pLast = nullptr; CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::GetFirst() { @@ -31,7 +31,7 @@ CAutoRegisterCommandHelper* CAutoRegisterCommandHelper::GetFirst() CAutoRegisterCommandHelper::CAutoRegisterCommandHelper(void(*registerFunc)(CEditorCommandManager &)) { m_registerFunc = registerFunc; - m_pNext = 0; + m_pNext = nullptr; if (!s_pLast) { diff --git a/Code/Editor/Commands/CommandManager.h b/Code/Editor/Commands/CommandManager.h index 2ec4a137bc..761c79f79c 100644 --- a/Code/Editor/Commands/CommandManager.h +++ b/Code/Editor/Commands/CommandManager.h @@ -38,7 +38,7 @@ public: void RegisterAutoCommands(); - bool AddCommand(CCommand* pCommand, TPfnDeleter deleter = NULL); + bool AddCommand(CCommand* pCommand, TPfnDeleter deleter = nullptr); bool UnregisterCommand(const char* module, const char* name); bool RegisterUICommand( const char* module, diff --git a/Code/Editor/Controls/BitmapToolTip.h b/Code/Editor/Controls/BitmapToolTip.h index d4bb89c625..5b7c56cbf3 100644 --- a/Code/Editor/Controls/BitmapToolTip.h +++ b/Code/Editor/Controls/BitmapToolTip.h @@ -42,7 +42,7 @@ public: CBitmapToolTip(QWidget* parent = nullptr); virtual ~CBitmapToolTip(); - BOOL Create(const RECT& rect); + bool Create(const RECT& rect); // Attributes public: diff --git a/Code/Editor/Controls/ColorGradientCtrl.cpp b/Code/Editor/Controls/ColorGradientCtrl.cpp index 555d285192..3bd3b11690 100644 --- a/Code/Editor/Controls/ColorGradientCtrl.cpp +++ b/Code/Editor/Controls/ColorGradientCtrl.cpp @@ -29,7 +29,7 @@ CColorGradientCtrl::CColorGradientCtrl(QWidget* parent) m_nHitKeyIndex = -1; m_nKeyDrawRadius = 3; m_bTracking = false; - m_pSpline = 0; + m_pSpline = nullptr; m_fMinTime = -1; m_fMaxTime = 1; m_fMinValue = -1; @@ -474,7 +474,7 @@ void CColorGradientCtrl::SetActiveKey(int nIndex) } ///////////////////////////////////////////////////////////////////////////// -void CColorGradientCtrl::SetSpline(ISplineInterpolator* pSpline, BOOL bRedraw) +void CColorGradientCtrl::SetSpline(ISplineInterpolator* pSpline, bool bRedraw) { if (pSpline != m_pSpline) { @@ -501,7 +501,7 @@ ISplineInterpolator* CColorGradientCtrl::GetSpline() ///////////////////////////////////////////////////////////////////////////// void CColorGradientCtrl::keyPressEvent(QKeyEvent* event) { - BOOL bProcessed = false; + bool bProcessed = false; if (m_nActiveKey != -1 && m_pSpline) { diff --git a/Code/Editor/Controls/ColorGradientCtrl.h b/Code/Editor/Controls/ColorGradientCtrl.h index 9533fecdfa..80d8b966f4 100644 --- a/Code/Editor/Controls/ColorGradientCtrl.h +++ b/Code/Editor/Controls/ColorGradientCtrl.h @@ -54,7 +54,7 @@ public: // Lock value of first and last key to be the same. void LockFirstAndLastKeys(bool bLock) { m_bLockFirstLastKey = bLock; } - void SetSpline(ISplineInterpolator* pSpline, BOOL bRedraw = FALSE); + void SetSpline(ISplineInterpolator* pSpline, bool bRedraw = false); ISplineInterpolator* GetSpline(); void SetTimeMarker(float fTime); diff --git a/Code/Editor/Controls/ConsoleSCB.cpp b/Code/Editor/Controls/ConsoleSCB.cpp index 9f1921395c..3fda904844 100644 --- a/Code/Editor/Controls/ConsoleSCB.cpp +++ b/Code/Editor/Controls/ConsoleSCB.cpp @@ -62,14 +62,14 @@ public: } protected: - void highlightBlock(const QString &text) + void highlightBlock(const QString &text) override { auto pos = -1; QTextCharFormat myClassFormat; myClassFormat.setFontWeight(QFont::Bold); myClassFormat.setBackground(Qt::yellow); - while (1) + while (true) { pos = text.indexOf(m_searchTerm, pos+1, Qt::CaseInsensitive); @@ -567,7 +567,7 @@ static CVarBlock* VarBlockFromConsoleVars() size_t cmdCount = console->GetSortedVars(&cmds[0], cmds.size()); CVarBlock* vb = new CVarBlock; - IVariable* pVariable = 0; + IVariable* pVariable = nullptr; for (int i = 0; i < cmdCount; i++) { ICVar* pCVar = console->GetCVar(cmds[i]); diff --git a/Code/Editor/Controls/HotTrackingTreeCtrl.cpp b/Code/Editor/Controls/HotTrackingTreeCtrl.cpp index 917d02155b..54152a9fd4 100644 --- a/Code/Editor/Controls/HotTrackingTreeCtrl.cpp +++ b/Code/Editor/Controls/HotTrackingTreeCtrl.cpp @@ -19,22 +19,22 @@ CHotTrackingTreeCtrl::CHotTrackingTreeCtrl(QWidget* parent) : QTreeWidget(parent) { setMouseTracking(true); - m_hHoverItem = NULL; + m_hHoverItem = nullptr; } void CHotTrackingTreeCtrl::mouseMoveEvent(QMouseEvent* event) { QTreeWidgetItem* hItem = itemAt(event->pos()); - if (m_hHoverItem != NULL) + if (m_hHoverItem != nullptr) { QFont font = m_hHoverItem->font(0); font.setBold(false); m_hHoverItem->setFont(0, font); - m_hHoverItem = NULL; + m_hHoverItem = nullptr; } - if (hItem != NULL) + if (hItem != nullptr) { QFont font = hItem->font(0); font.setBold(true); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp index 323fe2a07a..8651db7e96 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp @@ -27,7 +27,7 @@ void ReflectedPropertiesPanel::DeleteVars() { ClearVarBlock(); m_updateCallbacks.clear(); - m_varBlock = 0; + m_varBlock = nullptr; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp index 89938d9735..1a7060aa8d 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp @@ -198,7 +198,7 @@ void ReflectedPropertyControl::CreateItems(XmlNodeRef node) void ReflectedPropertyControl::CreateItems(XmlNodeRef node, CVarBlockPtr& outBlockPtr, IVariable::OnSetCallback* func, bool splitCamelCaseIntoWords) { - SelectItem(0); + SelectItem(nullptr); outBlockPtr = new CVarBlock; for (size_t i = 0, iGroupCount(node->getChildCount()); i < iGroupCount; ++i) @@ -505,7 +505,7 @@ void ReflectedPropertyControl::RemoveAllItems() void ReflectedPropertyControl::ClearVarBlock() { RemoveAllItems(); - m_pVarBlock = 0; + m_pVarBlock = nullptr; } void ReflectedPropertyControl::RecreateAllItems() @@ -688,11 +688,11 @@ void ReflectedPropertyControl::OnItemChange(ReflectedPropertyItem *item, bool de // callback until after the current event queue is processed, so that we aren't changing other widgets // as a ton of them are still being created. Qt::ConnectionType connectionType = deferCallbacks ? Qt::QueuedConnection : Qt::DirectConnection; - if (m_updateVarFunc != 0 && m_bEnableCallback) + if (m_updateVarFunc && m_bEnableCallback) { QMetaObject::invokeMethod(this, "DoUpdateCallback", connectionType, Q_ARG(IVariable*, item->GetVariable())); } - if (m_updateObjectFunc != 0 && m_bEnableCallback) + if (m_updateObjectFunc && m_bEnableCallback) { // KDAB: This callback has same signature as DoUpdateCallback. I think the only reason there are 2 is because some // EntityObject registers callback and some derived objects want to register their own callback. the normal UpdateCallback @@ -709,7 +709,7 @@ void ReflectedPropertyControl::DoUpdateCallback(IVariable *var) const bool variableStillExists = FindVariable(var); AZ_Assert(variableStillExists, "This variable and the item containing it were destroyed during a deferred callback. Change to non-deferred callback."); - if (m_updateVarFunc == 0 || !variableStillExists) + if (!m_updateVarFunc || !variableStillExists) { return; } @@ -724,7 +724,7 @@ void ReflectedPropertyControl::DoUpdateObjectCallback(IVariable *var) const bool variableStillExists = FindVariable(var); AZ_Assert(variableStillExists, "This variable and the item containing it were destroyed during a deferred callback. Change to non-deferred callback."); - if (m_updateVarFunc == 0 || !variableStillExists) + if ( !m_updateVarFunc || !variableStillExists) { return; } @@ -904,7 +904,7 @@ void ReflectedPropertyControl::SetUndoCallback(UndoCallback &callback) void ReflectedPropertyControl::ClearUndoCallback() { - m_undoFunc = 0; + m_undoFunc = nullptr; } bool ReflectedPropertyControl::FindVariable(IVariable *categoryItem) const diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp index 0bea6902c9..5a9d61be42 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp @@ -82,7 +82,7 @@ public: } //helps implement ReflectedPropertyControl::ReplaceVarBlock - void ReplaceVarBlock(CVarBlock *varBlock) + void ReplaceVarBlock(CVarBlock *varBlock) override { m_containerVar->Clear(); UpdateCommon(m_item->GetVariable(), varBlock); @@ -207,7 +207,7 @@ void ReflectedPropertyItem::SetVariable(IVariable *var) ReleaseVariable(); m_pVariable = pInputVar; - assert(m_pVariable != NULL); + assert(m_pVariable != nullptr); m_pVariable->AddOnSetCallback(&m_onSetCallback); m_pVariable->AddOnSetEnumCallback(&m_onSetEnumCallback); @@ -332,7 +332,7 @@ void ReflectedPropertyItem::RemoveAllChildren() { for (int i = 0; i < m_childs.size(); i++) { - m_childs[i]->m_parent = 0; + m_childs[i]->m_parent = nullptr; } m_childs.clear(); @@ -473,7 +473,7 @@ void ReflectedPropertyItem::ReleaseVariable() m_pVariable->RemoveOnSetCallback(&m_onSetCallback); m_pVariable->RemoveOnSetEnumCallback(&m_onSetEnumCallback); } - m_pVariable = 0; + m_pVariable = nullptr; delete m_reflectedVarAdapter; m_reflectedVarAdapter = nullptr; } diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp index 20e86c6838..5639fa95b0 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp @@ -473,7 +473,7 @@ void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable *pVariable) //extract the list of custom items from the IVariable user data IVariable::IGetCustomItems* pGetCustomItems = static_cast (pVariable->GetUserData().value()); - if (pGetCustomItems != 0) + if (pGetCustomItems != nullptr) { std::vector items; QString dlgTitle; diff --git a/Code/Editor/Controls/SplineCtrl.cpp b/Code/Editor/Controls/SplineCtrl.cpp index 63481d27df..d66fc16ade 100644 --- a/Code/Editor/Controls/SplineCtrl.cpp +++ b/Code/Editor/Controls/SplineCtrl.cpp @@ -30,7 +30,7 @@ CSplineCtrl::CSplineCtrl(QWidget* parent) m_nHitKeyIndex = -1; m_nKeyDrawRadius = 3; m_bTracking = false; - m_pSpline = 0; + m_pSpline = nullptr; m_gridX = 10; m_gridY = 10; m_fMinTime = -1; @@ -40,7 +40,7 @@ CSplineCtrl::CSplineCtrl(QWidget* parent) m_fTooltipScaleX = 1; m_fTooltipScaleY = 1; m_bLockFirstLastKey = false; - m_pTimelineCtrl = 0; + m_pTimelineCtrl = nullptr; m_bSelectedKeys.reserve(0); @@ -417,7 +417,7 @@ void CSplineCtrl::SetActiveKey(int nIndex) } ///////////////////////////////////////////////////////////////////////////// -void CSplineCtrl::SetSpline(ISplineInterpolator* pSpline, BOOL bRedraw) +void CSplineCtrl::SetSpline(ISplineInterpolator* pSpline, bool bRedraw) { if (pSpline != m_pSpline) { @@ -596,7 +596,7 @@ CSplineCtrl::EHitCode CSplineCtrl::HitTest(const QPoint& point) /////////////////////////////////////////////////////////////////////////////// void CSplineCtrl::StartTracking() { - m_bTracking = TRUE; + m_bTracking = true; GetIEditor()->BeginUndo(); @@ -674,7 +674,7 @@ void CSplineCtrl::StopTracking() GetIEditor()->AcceptUndo("Spline Move"); - m_bTracking = FALSE; + m_bTracking = false; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/Controls/SplineCtrl.h b/Code/Editor/Controls/SplineCtrl.h index e90fc1820e..ec5b3e52ce 100644 --- a/Code/Editor/Controls/SplineCtrl.h +++ b/Code/Editor/Controls/SplineCtrl.h @@ -59,7 +59,7 @@ public: // Lock value of first and last key to be the same. void LockFirstAndLastKeys(bool bLock) { m_bLockFirstLastKey = bLock; } - void SetSpline(ISplineInterpolator* pSpline, BOOL bRedraw = FALSE); + void SetSpline(ISplineInterpolator* pSpline, bool bRedraw = false); ISplineInterpolator* GetSpline(); void SetTimeMarker(float fTime); diff --git a/Code/Editor/Controls/SplineCtrlEx.cpp b/Code/Editor/Controls/SplineCtrlEx.cpp index 2afc3f16aa..36a9d8afef 100644 --- a/Code/Editor/Controls/SplineCtrlEx.cpp +++ b/Code/Editor/Controls/SplineCtrlEx.cpp @@ -69,8 +69,8 @@ protected: AbstractSplineWidget* pCtrl = FindControl(m_pCtrl); m_splineEntries.resize(m_splineEntries.size() + 1); SplineEntry& entry = m_splineEntries.back(); - ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : 0); - entry.id = (pSplineSet ? pSplineSet->GetIDFromSpline(pSpline) : 0); + ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : nullptr); + entry.id = (pSplineSet ? pSplineSet->GetIDFromSpline(pSpline) : nullptr); entry.pSpline = pSpline; const int numKeys = pSpline->GetKeyCount(); @@ -81,10 +81,10 @@ protected: } } - virtual int GetSize() { return sizeof(*this); } - virtual QString GetDescription() { return "UndoSplineCtrlEx"; }; + int GetSize() override { return sizeof(*this); } + QString GetDescription() override { return "UndoSplineCtrlEx"; }; - virtual void Undo(bool bUndo) + void Undo(bool bUndo) override { AbstractSplineWidget* pCtrl = FindControl(m_pCtrl); if (pCtrl) @@ -104,7 +104,7 @@ protected: } } - virtual void Redo() + void Redo() override { AbstractSplineWidget* pCtrl = FindControl(m_pCtrl); if (pCtrl) @@ -134,7 +134,7 @@ private: void SerializeSplines(_smart_ptr SplineEntry::* backup, bool bLoading) { AbstractSplineWidget* pCtrl = FindControl(m_pCtrl); - ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : 0); + ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : nullptr); for (auto it = m_splineEntries.begin(); it != m_splineEntries.end(); ++it) { SplineEntry& entry = *it; @@ -157,19 +157,19 @@ private: } public: - typedef std::list CSplineCtrls; + using CSplineCtrls = std::list; static AbstractSplineWidget* FindControl(AbstractSplineWidget* pCtrl) { if (!pCtrl) { - return 0; + return nullptr; } auto iter = std::find(s_activeCtrls.begin(), s_activeCtrls.end(), pCtrl); if (iter == s_activeCtrls.end()) { - return 0; + return nullptr; } return *iter; @@ -193,10 +193,10 @@ public: static CSplineCtrls s_activeCtrls; - virtual bool IsSelectionChanged() const + bool IsSelectionChanged() const override { AbstractSplineWidget* pCtrl = FindControl(m_pCtrl); - ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : 0); + ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : nullptr); for (auto it = m_splineEntries.begin(); it != m_splineEntries.end(); ++it) { @@ -256,11 +256,11 @@ SplineWidget::~SplineWidget() AbstractSplineWidget::AbstractSplineWidget() : m_defaultKeyTangentType(SPLINE_KEY_TANGENT_NONE) { - m_pTimelineCtrl = 0; + m_pTimelineCtrl = nullptr; m_totalSplineCount = 0; - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; m_nHitDimension = -1; m_bHitIncomingHandle = true; @@ -301,7 +301,7 @@ AbstractSplineWidget::AbstractSplineWidget() m_boLeftMouseButtonDown = false; - m_pSplineSet = 0; + m_pSplineSet = nullptr; m_controlAmplitude = false; @@ -1633,7 +1633,7 @@ void SplineWidget::wheelEvent(QWheelEvent* event) void SplineWidget::keyPressEvent(QKeyEvent* e) { - BOOL bProcessed = false; + bool bProcessed = false; switch (e->key()) { @@ -1780,7 +1780,7 @@ void AbstractSplineWidget::SetHorizontalExtent([[maybe_unused]] int min, [[maybe //si.nPage = max(0,m_rcClient.Width() - m_leftOffset*2); //si.nPage = 1; //si.nPage = 1; - SetScrollInfo( SB_HORZ,&si,TRUE ); + SetScrollInfo( SB_HORZ,&si,true ); */ } @@ -1792,7 +1792,7 @@ ISplineInterpolator* AbstractSplineWidget::HitSpline(const QPoint& point) return m_pHitSpline; } - return NULL; + return nullptr; } ////////////////////////////////////////////////////////////////////////////// @@ -1806,8 +1806,8 @@ AbstractSplineWidget::EHitCode AbstractSplineWidget::HitTest(const QPoint& point PointToTimeValue(point, time, val); m_hitCode = HIT_NOTHING; - m_pHitSpline = NULL; - m_pHitDetailSpline = NULL; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; m_nHitDimension = -1; m_bHitIncomingHandle = true; @@ -1968,8 +1968,8 @@ void AbstractSplineWidget::StopTracking() void AbstractSplineWidget::ScaleAmplitudeKeys(float time, float startValue, float offset) { //TODO: Test it in the facial animation pane and fix it... - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; m_nHitDimension = -1; @@ -2071,8 +2071,8 @@ void AbstractSplineWidget::TimeScaleKeys(float time, float startTime, float endT float timeScaleC = endTime - startTime * timeScaleM; // Loop through all keys that are selected. - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; float affectedRangeMin = FLT_MAX; @@ -2179,8 +2179,8 @@ void AbstractSplineWidget::ValueScaleKeys(float startValue, float endValue) } // Loop through all keys that are selected. - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; m_nHitDimension = -1; @@ -2212,8 +2212,8 @@ void AbstractSplineWidget::ValueScaleKeys(float startValue, float endValue) ////////////////////////////////////////////////////////////////////////// void AbstractSplineWidget::MoveSelectedKeys(Vec2 offset, bool copyKeys) { - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; m_nHitDimension = -1; @@ -2275,8 +2275,8 @@ void AbstractSplineWidget::RemoveKey(ISplineInterpolator* pSpline, int nKey) SendNotifyEvent(SPLN_BEFORE_CHANGE); - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; if (nKey != -1) { @@ -2294,8 +2294,8 @@ void AbstractSplineWidget::RemoveSelectedKeys() SendNotifyEvent(SPLN_BEFORE_CHANGE); - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; for (int splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex) @@ -2558,11 +2558,11 @@ public: }; void AbstractSplineWidget::DuplicateSelectedKeys() { - m_pHitSpline = 0; - m_pHitDetailSpline = 0; + m_pHitSpline = nullptr; + m_pHitDetailSpline = nullptr; m_nHitKeyIndex = -1; - typedef std::vector KeysToAddContainer; + using KeysToAddContainer = std::vector; KeysToAddContainer keysToInsert; for (int splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex) { @@ -2600,7 +2600,7 @@ void AbstractSplineWidget::ZeroAll() { GetIEditor()->BeginUndo(); - typedef std::vector SplineContainer; + using SplineContainer = std::vector; SplineContainer splines; for (int splineIndex = 0; splineIndex < int(m_splines.size()); ++splineIndex) { @@ -2632,7 +2632,7 @@ void AbstractSplineWidget::KeyAll() { GetIEditor()->BeginUndo(); - typedef std::vector SplineContainer; + using SplineContainer = std::vector; SplineContainer splines; for (int splineIndex = 0; splineIndex < int(m_splines.size()); ++splineIndex) { diff --git a/Code/Editor/Controls/TimelineCtrl.cpp b/Code/Editor/Controls/TimelineCtrl.cpp index d1590c5346..a5a941fc78 100644 --- a/Code/Editor/Controls/TimelineCtrl.cpp +++ b/Code/Editor/Controls/TimelineCtrl.cpp @@ -58,7 +58,7 @@ TimelineWidget::TimelineWidget(QWidget* parent /* = nullptr */) m_bIgnoreSetTime = false; - m_pKeyTimeSet = 0; + m_pKeyTimeSet = nullptr; m_markerStyle = MARKER_STYLE_SECONDS; m_fps = 30.0f; diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index 3c27c25c9a..b0e586031e 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -80,12 +80,12 @@ namespace , m_trigger(trigger) {} - virtual ~EditorListener() + ~EditorListener() override { GetIEditor()->UnregisterNotifyListener(this); } - void OnEditorNotifyEvent(EEditorNotifyEvent event) + void OnEditorNotifyEvent(EEditorNotifyEvent event) override { m_trigger(event); } diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp index 5a4763d8e8..0776a96a4d 100644 --- a/Code/Editor/Core/QtEditorApplication.cpp +++ b/Code/Editor/Core/QtEditorApplication.cpp @@ -423,7 +423,7 @@ namespace Editor { UINT rawInputSize; const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER); - GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize); + GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, nullptr, &rawInputSize, rawInputHeaderSize); AZStd::array rawInputBytesArray; LPBYTE rawInputBytes = rawInputBytesArray.data(); diff --git a/Code/Editor/Core/Tests/test_Main.cpp b/Code/Editor/Core/Tests/test_Main.cpp index c0772753c6..6acedb6e57 100644 --- a/Code/Editor/Core/Tests/test_Main.cpp +++ b/Code/Editor/Core/Tests/test_Main.cpp @@ -26,7 +26,7 @@ class EditorCoreTestEnvironment public: AZ_TEST_CLASS_ALLOCATOR(EditorCoreTestEnvironment); - virtual ~EditorCoreTestEnvironment() + ~EditorCoreTestEnvironment() override { } diff --git a/Code/Editor/Dialogs/ErrorsDlg.cpp b/Code/Editor/Dialogs/ErrorsDlg.cpp index e89a3a6ded..280ffbbab6 100644 --- a/Code/Editor/Dialogs/ErrorsDlg.cpp +++ b/Code/Editor/Dialogs/ErrorsDlg.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING -CErrorsDlg::CErrorsDlg(QWidget* pParent /*=NULL*/) +CErrorsDlg::CErrorsDlg(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , ui(new Ui::CErrorsDlg) { diff --git a/Code/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Editor/Dialogs/PythonScriptsDialog.cpp index 98365769bb..7c6b445387 100644 --- a/Code/Editor/Dialogs/PythonScriptsDialog.cpp +++ b/Code/Editor/Dialogs/PythonScriptsDialog.cpp @@ -159,7 +159,7 @@ void CPythonScriptsDialog::OnExecute() QList selectedItems = ui->treeView->GetSelectedItems(); QStandardItem* selectedItem = selectedItems.empty() ? nullptr : selectedItems.first(); - if (selectedItem == NULL) + if (selectedItem == nullptr) { return; } diff --git a/Code/Editor/Export/ExportManager.cpp b/Code/Editor/Export/ExportManager.cpp index 682dcf3980..10f96ce71b 100644 --- a/Code/Editor/Export/ExportManager.cpp +++ b/Code/Editor/Export/ExportManager.cpp @@ -96,7 +96,7 @@ Export::CObject::CObject(const char* pName) cameraTargetNodeName[0] = '\0'; - m_pLastObject = 0; + m_pLastObject = nullptr; } @@ -116,14 +116,14 @@ void Export::CData::Clear() // CExportManager CExportManager::CExportManager() : m_isPrecaching(false) - , m_pBaseObj(0) + , m_pBaseObj(nullptr) , m_FBXBakedExportFPS(0.0f) , m_fScale(100.0f) , // this scale is used by CryEngine RC m_bAnimationExport(false) , m_bExportLocalCoords(false) , m_numberOfExportFrames(0) - , m_pivotEntityObject(0) + , m_pivotEntityObject(nullptr) , m_bBakedKeysSequenceExport(true) , m_animTimeExportPrimarySequenceCurrentTime(0.0f) , m_animKeyTimeExport(true) @@ -290,7 +290,7 @@ void CExportManager::ProcessEntityAnimationTrack( const AZ::EntityId entityId, Export::CObject* pObj, AnimParamType entityTrackParamType) { CTrackViewAnimNode* pEntityNode = GetIEditor()->GetSequenceManager()->GetActiveAnimNode(entityId); - CTrackViewTrack* pEntityTrack = (pEntityNode ? pEntityNode->GetTrackForParameter(entityTrackParamType) : 0); + CTrackViewTrack* pEntityTrack = (pEntityNode ? pEntityNode->GetTrackForParameter(entityTrackParamType) : nullptr); if (!pEntityTrack) { @@ -397,7 +397,7 @@ void CExportManager::AddMesh(Export::CObject* pObj, const IIndexedMesh* pIndMesh else { Export::CMesh* pMesh = new Export::CMesh(); - if (meshDesc.m_nFaceCount == 0 && meshDesc.m_nIndexCount != 0 && meshDesc.m_pIndices != 0) + if (meshDesc.m_nFaceCount == 0 && meshDesc.m_nIndexCount != 0 && meshDesc.m_pIndices != nullptr) { const vtx_idx* pIndices = &meshDesc.m_pIndices[0]; int nTris = meshDesc.m_nIndexCount / 3; @@ -431,7 +431,7 @@ void CExportManager::AddMesh(Export::CObject* pObj, const IIndexedMesh* pIndMesh bool CExportManager::AddStatObj(Export::CObject* pObj, IStatObj* pStatObj, Matrix34A* pTm) { - IIndexedMesh* pIndMesh = 0; + IIndexedMesh* pIndMesh = nullptr; if (pStatObj->GetSubObjectCount()) { @@ -440,7 +440,7 @@ bool CExportManager::AddStatObj(Export::CObject* pObj, IStatObj* pStatObj, Matri IStatObj::SSubObject* pSubObj = pStatObj->GetSubObject(i); if (pSubObj && pSubObj->nType == STATIC_SUB_OBJECT_MESH && pSubObj->pStatObj) { - pIndMesh = 0; + pIndMesh = nullptr; if (m_isOccluder) { if (pSubObj->pStatObj->GetLodObject(2)) @@ -542,7 +542,7 @@ bool CExportManager::AddObject(CBaseObject* pBaseObj) if (m_isPrecaching) { - AddMeshes(0); + AddMeshes(nullptr); return true; } @@ -554,7 +554,7 @@ bool CExportManager::AddObject(CBaseObject* pBaseObj) m_objectMap[pBaseObj] = int(m_data.m_objects.size() - 1); AddMeshes(pObj); - m_pBaseObj = 0; + m_pBaseObj = nullptr; return true; } @@ -678,7 +678,7 @@ bool CExportManager::ProcessObjectsForExport() for (size_t objectID = 0; objectID < m_data.m_objects.size(); ++objectID) { Export::CObject* pObj2 = m_data.m_objects[objectID]; - CBaseObject* pObject = 0; + CBaseObject* pObject = nullptr; if (QString::compare(pObj2->name, kPrimaryCameraName) == 0) { @@ -983,7 +983,7 @@ bool CExportManager::AddObjectsFromSequence(CTrackViewSequence* pSequence, XmlNo { if (pSubSequence && !pSubSequence->IsDisabled()) { - XmlNodeRef subSeqNode = 0; + XmlNodeRef subSeqNode = nullptr; if (!seqNode) { diff --git a/Code/Editor/Export/OBJExporter.cpp b/Code/Editor/Export/OBJExporter.cpp index 893512e236..bd2696090e 100644 --- a/Code/Editor/Export/OBJExporter.cpp +++ b/Code/Editor/Export/OBJExporter.cpp @@ -67,7 +67,7 @@ bool COBJExporter::ExportToFile(const char* filename, const Export::IData* pExpo while (nParent >= 0 && nParent < pExportData->GetObjectCount()) { const Export::Object* pParentObj = pExportData->GetObject(nParent); - assert(NULL != pParentObj); + assert(nullptr != pParentObj); Vec3 pos2(pParentObj->pos.x, pParentObj->pos.y, pParentObj->pos.z); Quat rot2(pParentObj->rot.w, pParentObj->rot.v.x, pParentObj->rot.v.y, pParentObj->rot.v.z); diff --git a/Code/Editor/Geometry/TriMesh.cpp b/Code/Editor/Geometry/TriMesh.cpp index fe755ca6c3..737886cabc 100644 --- a/Code/Editor/Geometry/TriMesh.cpp +++ b/Code/Editor/Geometry/TriMesh.cpp @@ -19,13 +19,13 @@ ////////////////////////////////////////////////////////////////////////// CTriMesh::CTriMesh() { - pFaces = NULL; - pVertices = NULL; - pWSVertices = NULL; - pUV = NULL; - pColors = NULL; - pEdges = NULL; - pWeights = NULL; + pFaces = nullptr; + pVertices = nullptr; + pWSVertices = nullptr; + pUV = nullptr; + pColors = nullptr; + pEdges = nullptr; + pWeights = nullptr; nFacesCount = 0; nVertCount = 0; @@ -67,7 +67,7 @@ void CTriMesh::ReallocStream(int stream, int nNewCount) { return; // Stream already have required size. } - void* pStream = 0; + void* pStream = nullptr; int nElementSize = 0; GetStreamInfo(stream, pStream, nElementSize); pStream = ReAllocElements(pStream, nNewCount, nElementSize); @@ -256,7 +256,7 @@ void CTriMesh::SharePositions() std::vector arrHashTable[256]; CTriVertex* pNewVerts = new CTriVertex[GetVertexCount()]; - SMeshColor* pNewColors = 0; + SMeshColor* pNewColors = nullptr; if (pColors) { pNewColors = new SMeshColor[GetVertexCount()]; @@ -433,8 +433,8 @@ void CTriMesh::UpdateIndexedMesh(IIndexedMesh* pIndexedMesh) const ////////////////////////////////////////////////////////////////////////// void CTriMesh::CopyStream(CTriMesh& fromMesh, int stream) { - void* pTrgStream = 0; - void* pSrcStream = 0; + void* pTrgStream = nullptr; + void* pSrcStream = nullptr; int nElemSize = 0; fromMesh.GetStreamInfo(stream, pSrcStream, nElemSize); if (pSrcStream) diff --git a/Code/Editor/Include/IAssetItem.h b/Code/Editor/Include/IAssetItem.h index 892d347431..ff80331af5 100644 --- a/Code/Editor/Include/IAssetItem.h +++ b/Code/Editor/Include/IAssetItem.h @@ -334,12 +334,12 @@ struct IAssetItem virtual void OnEndPreview() = 0; // Description: // If the asset has a special preview panel with utility controls, to be placed at the top of the Preview window, it can return an child dialog window - // otherwise it can return NULL, if no panel is available + // otherwise it can return nullptr, if no panel is available // Arguments: - // pParentWnd - a valid CDialog*, or NULL + // pParentWnd - a valid CDialog*, or nullptr // Return Value: // A valid child dialog window handle, if this asset wants to have a custom panel in the top side of the Asset Preview window, - // otherwise it can return NULL, if no panel is available + // otherwise it can return nullptr, if no panel is available // See Also: // OnBeginPreview(), OnEndPreview() virtual QWidget* GetCustomPreviewPanelHeader(QWidget* pParentWnd) = 0; diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h index f402786e67..f83c7e0d59 100644 --- a/Code/Editor/Include/IFileUtil.h +++ b/Code/Editor/Include/IFileUtil.h @@ -186,8 +186,15 @@ struct IFileUtil virtual ECopyTreeResult CopyTree(const QString& strSourceDirectory, const QString& strTargetDirectory, bool boRecurse = true, bool boConfirmOverwrite = false) = 0; ////////////////////////////////////////////////////////////////////////// - // @param LPPROGRESS_ROUTINE pfnProgress - called by the system to notify of file copy progress - // @param LPBOOL pbCancel - when the contents of this BOOL are set to TRUE, the system cancels the copy operation + /** + * @brief CopyFile + * @param strSourceFile + * @param strTargetFile + * @param boConfirmOverwrite + * @param pfnProgress - called by the system to notify of file copy progress + * @param pbCancel - when the contents of this bool are set to true, the system cancels the copy operation + * @return + */ virtual ECopyTreeResult CopyFile(const QString& strSourceFile, const QString& strTargetFile, bool boConfirmOverwrite = false, ProgressRoutine pfnProgress = nullptr, bool* pbCancel = nullptr) = 0; // As we don't have a FileUtil interface here, we have to duplicate some code :-( in order to keep From c6760d8935c9afbebecca82c6237bfb7de304fe9 Mon Sep 17 00:00:00 2001 From: Nemerle Date: Thu, 5 Aug 2021 16:48:00 +0200 Subject: [PATCH 02/18] Editor code: tidy up BOOLs,NULLs and overrides pt3. A few 'typedefs' replaced by 'using's This shouldn't have any functional changes at all, just c++17 modernization It's a part 3 of a split #2847 Signed-off-by: Nemerle --- Code/Editor/QtUI/QCollapsibleGroupBox.cpp | 2 +- Code/Editor/RenderHelpers/AxisHelper.h | 2 +- .../TrackView/2DBezierKeyUIControls.cpp | 10 ++++---- .../TrackView/AssetBlendKeyUIControls.cpp | 10 ++++---- .../Editor/TrackView/CaptureKeyUIControls.cpp | 10 ++++---- .../TrackView/CharacterKeyUIControls.cpp | 10 ++++---- .../Editor/TrackView/CommentKeyUIControls.cpp | 14 +++++------ Code/Editor/TrackView/CommentNodeAnimator.cpp | 2 +- .../Editor/TrackView/ConsoleKeyUIControls.cpp | 10 ++++---- Code/Editor/TrackView/EventKeyUIControls.cpp | 14 +++++------ Code/Editor/TrackView/GotoKeyUIControls.cpp | 10 ++++---- .../TrackView/ScreenFaderKeyUIControls.cpp | 14 +++++------ Code/Editor/TrackView/SelectKeyUIControls.cpp | 18 +++++++------- .../TrackView/SequenceBatchRenderDialog.cpp | 15 ++++++------ .../TrackView/SequenceBatchRenderDialog.h | 6 ++--- .../TrackView/SequenceKeyUIControls.cpp | 14 +++++------ Code/Editor/TrackView/SoundKeyUIControls.cpp | 10 ++++---- .../TrackView/TVCustomizeTrackColorsDlg.cpp | 2 +- Code/Editor/TrackView/TVEventsDialog.cpp | 2 +- Code/Editor/TrackView/TVSequenceProps.cpp | 6 ++--- Code/Editor/TrackView/TVSequenceProps.h | 4 ++-- .../TrackView/TimeRangeKeyUIControls.cpp | 10 ++++---- .../TrackView/TrackEventKeyUIControls.cpp | 12 +++++----- Code/Editor/TrackView/TrackViewAnimNode.cpp | 4 ++-- Code/Editor/TrackView/TrackViewDialog.cpp | 18 +++++++------- Code/Editor/TrackView/TrackViewDialog.h | 4 ++-- .../TrackView/TrackViewDopeSheetBase.cpp | 24 +++++++++---------- Code/Editor/TrackView/TrackViewFindDlg.cpp | 4 ++-- Code/Editor/TrackView/TrackViewFindDlg.h | 2 +- .../TrackView/TrackViewKeyPropertiesDlg.cpp | 4 ++-- .../TrackView/TrackViewKeyPropertiesDlg.h | 2 +- Code/Editor/TrackView/TrackViewNodes.cpp | 16 ++++++------- Code/Editor/TrackView/TrackViewSplineCtrl.cpp | 22 ++++++++--------- 33 files changed, 153 insertions(+), 154 deletions(-) diff --git a/Code/Editor/QtUI/QCollapsibleGroupBox.cpp b/Code/Editor/QtUI/QCollapsibleGroupBox.cpp index e1d3f59510..7fe56285e6 100644 --- a/Code/Editor/QtUI/QCollapsibleGroupBox.cpp +++ b/Code/Editor/QtUI/QCollapsibleGroupBox.cpp @@ -13,7 +13,7 @@ QCollapsibleGroupBox::QCollapsibleGroupBox(QWidget* parent) : QGroupBox(parent) , m_collapsed(false) - , m_toggleButton(0) + , m_toggleButton(nullptr) { m_toggleButton = new QToolButton(this); m_toggleButton->setFixedSize(16, 16); diff --git a/Code/Editor/RenderHelpers/AxisHelper.h b/Code/Editor/RenderHelpers/AxisHelper.h index b7d246d48c..70dcd2dae2 100644 --- a/Code/Editor/RenderHelpers/AxisHelper.h +++ b/Code/Editor/RenderHelpers/AxisHelper.h @@ -60,7 +60,7 @@ public: void DrawDome(const Matrix34& worldTM, const SGizmoParameters& setup, DisplayContext& dc, AABB& objectBox); bool HitTest(const Matrix34& worldTM, const SGizmoParameters& setup, HitContext& hc); - bool HitTestForRotationCircle(const Matrix34& worldTM, IDisplayViewport* view, const QPoint& pos, float fHitWidth, Vec3* pOutHitPos = NULL, Vec3* pOutHitNormal = NULL); + bool HitTestForRotationCircle(const Matrix34& worldTM, IDisplayViewport* view, const QPoint& pos, float fHitWidth, Vec3* pOutHitPos = nullptr, Vec3* pOutHitNormal = nullptr); void SetHighlightAxis(int axis) { m_highlightAxis = axis; }; int GetHighlightAxis() const { return m_highlightAxis; }; diff --git a/Code/Editor/TrackView/2DBezierKeyUIControls.cpp b/Code/Editor/TrackView/2DBezierKeyUIControls.cpp index 1709ea2eac..81cd151373 100644 --- a/Code/Editor/TrackView/2DBezierKeyUIControls.cpp +++ b/Code/Editor/TrackView/2DBezierKeyUIControls.cpp @@ -26,19 +26,19 @@ public: CSmartVariableArray mv_table; CSmartVariable mv_value; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_value, "Value"); } - bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return trackType == eAnimCurveType_BezierFloat; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 0; } + unsigned int GetPriority() const override { return 0; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/AssetBlendKeyUIControls.cpp b/Code/Editor/TrackView/AssetBlendKeyUIControls.cpp index a8e24cf58d..038a9d9780 100644 --- a/Code/Editor/TrackView/AssetBlendKeyUIControls.cpp +++ b/Code/Editor/TrackView/AssetBlendKeyUIControls.cpp @@ -41,7 +41,7 @@ public: CSmartVariable mv_blendInTime; CSmartVariable mv_blendOutTime; - virtual void OnCreateVars() + void OnCreateVars() override { // Init to an invalid id AZ::Data::AssetId assetId; @@ -62,15 +62,15 @@ public: mv_timeScale->SetLimits(0.001f, 100.f); } - bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const + bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const override { return valueType == AnimValueType::AssetBlend; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/CaptureKeyUIControls.cpp b/Code/Editor/TrackView/CaptureKeyUIControls.cpp index 821066d4a3..e6d88a6cd6 100644 --- a/Code/Editor/TrackView/CaptureKeyUIControls.cpp +++ b/Code/Editor/TrackView/CaptureKeyUIControls.cpp @@ -27,7 +27,7 @@ public: CSmartVariable mv_folder; CSmartVariable mv_once; - virtual void OnCreateVars() + void OnCreateVars() override { mv_duration.GetVar()->SetLimits(0, 100000.0f); mv_timeStep.GetVar()->SetLimits(0.001f, 1.0f); @@ -39,14 +39,14 @@ public: AddVariable(mv_table, mv_folder, "Output Folder"); AddVariable(mv_table, mv_once, "Just one frame?"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::Capture; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/CharacterKeyUIControls.cpp b/Code/Editor/TrackView/CharacterKeyUIControls.cpp index 9ff41f1275..24bfd9f680 100644 --- a/Code/Editor/TrackView/CharacterKeyUIControls.cpp +++ b/Code/Editor/TrackView/CharacterKeyUIControls.cpp @@ -33,7 +33,7 @@ public: CSmartVariable mv_endTime; CSmartVariable mv_timeScale; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_animation, "Animation", IVariable::DT_ANIMATION); @@ -45,14 +45,14 @@ public: AddVariable(mv_table, mv_timeScale, "Time Scale"); mv_timeScale->SetLimits(0.001f, 100.f); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const override { return paramType == AnimParamType::Animation || valueType == AnimValueType::CharacterAnim; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/CommentKeyUIControls.cpp b/Code/Editor/TrackView/CommentKeyUIControls.cpp index 4c5dc10bfa..b5a706c843 100644 --- a/Code/Editor/TrackView/CommentKeyUIControls.cpp +++ b/Code/Editor/TrackView/CommentKeyUIControls.cpp @@ -30,7 +30,7 @@ public: CSmartVariableEnum mv_font; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_comment, "Comment"); @@ -41,13 +41,13 @@ public: AddVariable(mv_table, mv_color, "Color", IVariable::DT_COLOR); - mv_align->SetEnumList(NULL); + mv_align->SetEnumList(nullptr); mv_align->AddEnumItem("Left", ICommentKey::eTA_Left); mv_align->AddEnumItem("Center", ICommentKey::eTA_Center); mv_align->AddEnumItem("Right", ICommentKey::eTA_Right); AddVariable(mv_table, mv_align, "Align"); - mv_font->SetEnumList(NULL); + mv_font->SetEnumList(nullptr); IFileUtil::FileArray fa; CFileUtil::ScanDirectory((Path::GetEditingGameDataFolder() + "/Fonts/").c_str(), "*.xml", fa, true); for (size_t i = 0; i < fa.size(); ++i) @@ -58,14 +58,14 @@ public: } AddVariable(mv_table, mv_font, "Font"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::CommentText; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/CommentNodeAnimator.cpp b/Code/Editor/TrackView/CommentNodeAnimator.cpp index 47f4c5d9ae..15dcce1566 100644 --- a/Code/Editor/TrackView/CommentNodeAnimator.cpp +++ b/Code/Editor/TrackView/CommentNodeAnimator.cpp @@ -26,7 +26,7 @@ CCommentNodeAnimator::CCommentNodeAnimator(CTrackViewAnimNode* pCommentNode) CCommentNodeAnimator::~CCommentNodeAnimator() { - m_pCommentNode = 0; + m_pCommentNode = nullptr; } void CCommentNodeAnimator::Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac) diff --git a/Code/Editor/TrackView/ConsoleKeyUIControls.cpp b/Code/Editor/TrackView/ConsoleKeyUIControls.cpp index cbf22f63e6..7bf23e0b52 100644 --- a/Code/Editor/TrackView/ConsoleKeyUIControls.cpp +++ b/Code/Editor/TrackView/ConsoleKeyUIControls.cpp @@ -24,19 +24,19 @@ public: CSmartVariableArray mv_table; CSmartVariable mv_command; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_command, "Command"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::Console; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/EventKeyUIControls.cpp b/Code/Editor/TrackView/EventKeyUIControls.cpp index a45e59dc1a..56b16d7c02 100644 --- a/Code/Editor/TrackView/EventKeyUIControls.cpp +++ b/Code/Editor/TrackView/EventKeyUIControls.cpp @@ -26,7 +26,7 @@ public: CSmartVariable mv_value; CSmartVariable mv_notrigger_in_scrubbing; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_event, "Event"); @@ -35,14 +35,14 @@ public: AddVariable(mv_deprecated, "Deprecated"); AddVariable(mv_deprecated, mv_animation, "Animation"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::Event; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { @@ -73,8 +73,8 @@ bool CEventKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType(); if (paramType == AnimParamType::Event) { - mv_event.SetEnumList(NULL); - mv_animation.SetEnumList(NULL); + mv_event.SetEnumList(nullptr); + mv_animation.SetEnumList(nullptr); // Add for empty, unset event mv_event->AddEnumItem(QObject::tr(""), ""); diff --git a/Code/Editor/TrackView/GotoKeyUIControls.cpp b/Code/Editor/TrackView/GotoKeyUIControls.cpp index 6435745d2a..c48ce4c5ad 100644 --- a/Code/Editor/TrackView/GotoKeyUIControls.cpp +++ b/Code/Editor/TrackView/GotoKeyUIControls.cpp @@ -24,12 +24,12 @@ public: CSmartVariableArray mv_table; CSmartVariable mv_command; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_command, "Goto Time"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { if (paramType == AnimParamType::Goto) { @@ -40,10 +40,10 @@ public: return false; } } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/ScreenFaderKeyUIControls.cpp b/Code/Editor/TrackView/ScreenFaderKeyUIControls.cpp index 786016cb37..a62ab17cbf 100644 --- a/Code/Editor/TrackView/ScreenFaderKeyUIControls.cpp +++ b/Code/Editor/TrackView/ScreenFaderKeyUIControls.cpp @@ -33,23 +33,23 @@ class CScreenFaderKeyUIControls public: //----------------------------------------------------------------------------- //! - virtual bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::ScreenFader; } //----------------------------------------------------------------------------- //! - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); - mv_fadeType->SetEnumList(NULL); + mv_fadeType->SetEnumList(nullptr); mv_fadeType->AddEnumItem("FadeIn", IScreenFaderKey::eFT_FadeIn); mv_fadeType->AddEnumItem("FadeOut", IScreenFaderKey::eFT_FadeOut); AddVariable(mv_table, mv_fadeType, "Type"); - mv_fadechangeType->SetEnumList(NULL); + mv_fadechangeType->SetEnumList(nullptr); mv_fadechangeType->AddEnumItem("Linear", IScreenFaderKey::eFCT_Linear); mv_fadechangeType->AddEnumItem("Square", IScreenFaderKey::eFCT_Square); mv_fadechangeType->AddEnumItem("Cubic Square", IScreenFaderKey::eFCT_CubicSquare); @@ -67,13 +67,13 @@ public: //----------------------------------------------------------------------------- //! - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& keys); + bool OnKeySelectionChange(CTrackViewKeyBundle& keys) override; //----------------------------------------------------------------------------- //! - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& keys); + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& keys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/SelectKeyUIControls.cpp b/Code/Editor/TrackView/SelectKeyUIControls.cpp index 37acf105f3..d12f449c73 100644 --- a/Code/Editor/TrackView/SelectKeyUIControls.cpp +++ b/Code/Editor/TrackView/SelectKeyUIControls.cpp @@ -22,7 +22,7 @@ class CSelectKeyUIControls , protected AZ::EntitySystemBus::Handler { public: - CSelectKeyUIControls() {} + CSelectKeyUIControls() = default; ~CSelectKeyUIControls() override; @@ -30,7 +30,7 @@ public: CSmartVariableEnum mv_camera; CSmartVariable mv_BlendTime; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_camera, "Camera"); @@ -39,14 +39,14 @@ public: Camera::CameraNotificationBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); } - bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const + bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const override { return valueType == AnimValueType::Select; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { @@ -98,7 +98,7 @@ bool CSelectKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKey ResetCameraEntries(); // Get All cameras. - mv_camera.SetEnumList(NULL); + mv_camera.SetEnumList(nullptr); mv_camera->AddEnumItem(QObject::tr(""), QString::number(static_cast(AZ::EntityId::InvalidEntityId))); @@ -217,7 +217,7 @@ void CSelectKeyUIControls::OnCameraRemoved(const AZ::EntityId & cameraId) // We can't iterate or remove an item from the enum list, and Camera::CameraRequests::GetCameras // still includes the deleted camera at this point. Reset the list anyway and filter out the // deleted camera. - mv_camera->SetEnumList(NULL); + mv_camera->SetEnumList(nullptr); mv_camera->AddEnumItem(QObject::tr(""), QString::number(static_cast(AZ::EntityId::InvalidEntityId))); AZ::EBusAggregateResults cameraComponentEntities; @@ -256,7 +256,7 @@ void CSelectKeyUIControls::OnEntityNameChanged(const AZ::EntityId & entityId, [[ void CSelectKeyUIControls::ResetCameraEntries() { - mv_camera.SetEnumList(NULL); + mv_camera.SetEnumList(nullptr); mv_camera->AddEnumItem(QObject::tr(""), QString::number(static_cast(AZ::EntityId::InvalidEntityId))); // Find all Component Entity Cameras diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index 7b08b3e614..4a56b2389b 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -117,8 +117,7 @@ CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pPare } CSequenceBatchRenderDialog::~CSequenceBatchRenderDialog() -{ -} += default; void CSequenceBatchRenderDialog::reject() { @@ -519,7 +518,7 @@ void CSequenceBatchRenderDialog::OnGo() InitializeContext(); // Trigger the first item. - OnMovieEvent(IMovieListener::eMovieEvent_Stopped, NULL); + OnMovieEvent(IMovieListener::eMovieEvent_Stopped, nullptr); } } @@ -728,7 +727,7 @@ bool CSequenceBatchRenderDialog::GetResolutionFromCustomResText(const char* cust bool CSequenceBatchRenderDialog::LoadOutputOptions(const QString& pathname) { XmlNodeRef batchRenderOptionsNode = XmlHelpers::LoadXmlFromFile(pathname.toStdString().c_str()); - if (batchRenderOptionsNode == NULL) + if (batchRenderOptionsNode == nullptr) { return true; } @@ -1391,7 +1390,7 @@ void CSequenceBatchRenderDialog::OnLoadBatch() Path::GetUserSandboxFolder(), loadPath)) { XmlNodeRef batchRenderListNode = XmlHelpers::LoadXmlFromFile(loadPath.toStdString().c_str()); - if (batchRenderListNode == NULL) + if (batchRenderListNode == nullptr) { return; } @@ -1414,7 +1413,7 @@ void CSequenceBatchRenderDialog::OnLoadBatch() // sequence const QString seqName = itemNode->getAttr("sequence"); item.pSequence = GetIEditor()->GetMovieSystem()->FindLegacySequenceByName(seqName.toUtf8().data()); - if (item.pSequence == NULL) + if (item.pSequence == nullptr) { QMessageBox::warning(this, tr("Sequence not found"), tr("A sequence of '%1' not found! This'll be skipped.").arg(seqName)); continue; @@ -1431,7 +1430,7 @@ void CSequenceBatchRenderDialog::OnLoadBatch() break; } } - if (item.pDirectorNode == NULL) + if (item.pDirectorNode == nullptr) { QMessageBox::warning(this, tr("Director node not found"), tr("A director node of '%1' not found in the sequence of '%2'! This'll be skipped.").arg(directorName).arg(seqName)); continue; @@ -1544,7 +1543,7 @@ bool CSequenceBatchRenderDialog::SetUpNewRenderItem(SRenderItem& item) break; } } - if (item.pDirectorNode == NULL) + if (item.pDirectorNode == nullptr) { return false; } diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.h b/Code/Editor/TrackView/SequenceBatchRenderDialog.h index 2d2097fa7a..5d8934f783 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.h +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.h @@ -81,8 +81,8 @@ protected: bool disableDebugInfo; bool bCreateVideo; SRenderItem() - : pSequence(NULL) - , pDirectorNode(NULL) + : pSequence(nullptr) + , pDirectorNode(nullptr) , disableDebugInfo(false) , bCreateVideo(false) {} bool operator==(const SRenderItem& item) @@ -155,7 +155,7 @@ protected: , expectedTotalTime(0) , spentTime(0) , flagBU(0) - , pActiveDirectorBU(NULL) + , pActiveDirectorBU(nullptr) , cvarCustomResWidthBU(0) , cvarCustomResHeightBU(0) , cvarDisplayInfoBU(0) diff --git a/Code/Editor/TrackView/SequenceKeyUIControls.cpp b/Code/Editor/TrackView/SequenceKeyUIControls.cpp index 5ef5a9c4ab..7889b30848 100644 --- a/Code/Editor/TrackView/SequenceKeyUIControls.cpp +++ b/Code/Editor/TrackView/SequenceKeyUIControls.cpp @@ -27,7 +27,7 @@ public: CSmartVariable mv_startTime; CSmartVariable mv_endTime; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_sequence, "Sequence"); @@ -35,14 +35,14 @@ public: AddVariable(mv_table, mv_startTime, "Start Time"); AddVariable(mv_table, mv_endTime, "End Time"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::Sequence; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { @@ -78,7 +78,7 @@ bool CSequenceKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedK ///////////////////////////////////////////////////////////////////////////////// // fill sequence comboBox with available sequences - mv_sequence.SetEnumList(NULL); + mv_sequence.SetEnumList(nullptr); // Insert '' empty enum mv_sequence->AddEnumItem(QObject::tr(""), CTrackViewDialog::GetEntityIdAsString(AZ::EntityId(AZ::EntityId::InvalidEntityId))); @@ -193,7 +193,7 @@ void CSequenceKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& se IMovieSystem* pMovieSystem = GetIEditor()->GetSystem()->GetIMovieSystem(); - if (pMovieSystem != NULL) + if (pMovieSystem != nullptr) { pMovieSystem->SetStartEndTime(pSequence, sequenceKey.fStartTime, sequenceKey.fEndTime); } diff --git a/Code/Editor/TrackView/SoundKeyUIControls.cpp b/Code/Editor/TrackView/SoundKeyUIControls.cpp index ff6b558abf..8c18b58aed 100644 --- a/Code/Editor/TrackView/SoundKeyUIControls.cpp +++ b/Code/Editor/TrackView/SoundKeyUIControls.cpp @@ -29,7 +29,7 @@ public: CSmartVariable mv_duration; CSmartVariable mv_customColor; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_startTrigger, "StartTrigger", IVariable::DT_AUDIO_TRIGGER); @@ -38,14 +38,14 @@ public: AddVariable(mv_options, "Options"); AddVariable(mv_options, mv_customColor, "Custom Color", IVariable::DT_COLOR); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::Sound; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/TVCustomizeTrackColorsDlg.cpp b/Code/Editor/TrackView/TVCustomizeTrackColorsDlg.cpp index e03b013720..e2f8a4f7a2 100644 --- a/Code/Editor/TrackView/TVCustomizeTrackColorsDlg.cpp +++ b/Code/Editor/TrackView/TVCustomizeTrackColorsDlg.cpp @@ -344,7 +344,7 @@ void CTVCustomizeTrackColorsDlg::Export(const QString& fullPath) const bool CTVCustomizeTrackColorsDlg::Import(const QString& fullPath) { XmlNodeRef customTrackColorsNode = XmlHelpers::LoadXmlFromFile(fullPath.toStdString().c_str()); - if (customTrackColorsNode == NULL) + if (customTrackColorsNode == nullptr) { return false; } diff --git a/Code/Editor/TrackView/TVEventsDialog.cpp b/Code/Editor/TrackView/TVEventsDialog.cpp index a89c0aac2a..c8221b38cd 100644 --- a/Code/Editor/TrackView/TVEventsDialog.cpp +++ b/Code/Editor/TrackView/TVEventsDialog.cpp @@ -211,7 +211,7 @@ public: int GetNumberOfUsageAndFirstTimeUsed(const char* eventName, float& timeFirstUsed) const; }; -CTVEventsDialog::CTVEventsDialog(QWidget* pParent /*=NULL*/) +CTVEventsDialog::CTVEventsDialog(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , m_ui(new Ui::TVEventsDialog) { diff --git a/Code/Editor/TrackView/TVSequenceProps.cpp b/Code/Editor/TrackView/TVSequenceProps.cpp index 3a0fab2f2c..1ac31d7e2b 100644 --- a/Code/Editor/TrackView/TVSequenceProps.cpp +++ b/Code/Editor/TrackView/TVSequenceProps.cpp @@ -51,7 +51,7 @@ CTVSequenceProps::~CTVSequenceProps() } // CTVSequenceProps message handlers -BOOL CTVSequenceProps::OnInitDialog() +bool CTVSequenceProps::OnInitDialog() { ui->NAME->setText(m_pSequence->GetName()); int seqFlags = m_pSequence->GetFlags(); @@ -97,7 +97,7 @@ BOOL CTVSequenceProps::OnInitDialog() ui->ORT_ONCE->setChecked(true); } - return TRUE; // return TRUE unless you set the focus to a control + return true; // return true unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } @@ -259,7 +259,7 @@ void CTVSequenceProps::OnOK() void CTVSequenceProps::ToggleCutsceneOptions(bool bActivated) { - if (bActivated == FALSE) + if (bActivated == false) { ui->NOABORT->setChecked(false); ui->DISABLEPLAYER->setChecked(false); diff --git a/Code/Editor/TrackView/TVSequenceProps.h b/Code/Editor/TrackView/TVSequenceProps.h index f12c245c57..b54208e429 100644 --- a/Code/Editor/TrackView/TVSequenceProps.h +++ b/Code/Editor/TrackView/TVSequenceProps.h @@ -28,7 +28,7 @@ class CTVSequenceProps { Q_OBJECT public: - CTVSequenceProps(CTrackViewSequence* pSequence, float fps, QWidget* pParent = NULL); // standard constructor + CTVSequenceProps(CTrackViewSequence* pSequence, float fps, QWidget* pParent = nullptr); // standard constructor ~CTVSequenceProps(); private: @@ -39,7 +39,7 @@ private: }; CTrackViewSequence* m_pSequence; - virtual BOOL OnInitDialog(); + virtual bool OnInitDialog(); virtual void OnOK(); void MoveScaleKeys(); diff --git a/Code/Editor/TrackView/TimeRangeKeyUIControls.cpp b/Code/Editor/TrackView/TimeRangeKeyUIControls.cpp index bd771e3849..e35c18329b 100644 --- a/Code/Editor/TrackView/TimeRangeKeyUIControls.cpp +++ b/Code/Editor/TrackView/TimeRangeKeyUIControls.cpp @@ -27,7 +27,7 @@ public: CSmartVariable mv_timeScale; CSmartVariable mv_bLoop; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_startTime, "Start Time"); @@ -36,14 +36,14 @@ public: AddVariable(mv_table, mv_bLoop, "Loop"); mv_timeScale->SetLimits(0.001f, 100.f); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::TimeRanges; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { diff --git a/Code/Editor/TrackView/TrackEventKeyUIControls.cpp b/Code/Editor/TrackView/TrackEventKeyUIControls.cpp index 934820ede1..035087733b 100644 --- a/Code/Editor/TrackView/TrackEventKeyUIControls.cpp +++ b/Code/Editor/TrackView/TrackEventKeyUIControls.cpp @@ -26,21 +26,21 @@ public: CSmartVariableEnum mv_event; CSmartVariable mv_value; - virtual void OnCreateVars() + void OnCreateVars() override { AddVariable(mv_table, "Key Properties"); AddVariable(mv_table, mv_event, "Track Event"); mv_event->SetFlags(mv_event->GetFlags() | IVariable::UI_UNSORTED); AddVariable(mv_table, mv_value, "Value"); } - bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const + bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const override { return paramType == AnimParamType::TrackEvent; } - virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys); - virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys); + bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys) override; + void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys) override; - virtual unsigned int GetPriority() const { return 1; } + unsigned int GetPriority() const override { return 1; } static const GUID& GetClassID() { @@ -182,7 +182,7 @@ void CTrackEventKeyUIControls::BuildEventDropDown(QString& curEvent, const QStri { bool curEventExists = false; bool addedEventExists = false; - mv_event.SetEnumList(NULL); + mv_event.SetEnumList(nullptr); const int eventCount = sequence->GetTrackEventsCount(); // Need to check if event exists before adding all events diff --git a/Code/Editor/TrackView/TrackViewAnimNode.cpp b/Code/Editor/TrackView/TrackViewAnimNode.cpp index c66ea5635c..9050808d3b 100644 --- a/Code/Editor/TrackView/TrackViewAnimNode.cpp +++ b/Code/Editor/TrackView/TrackViewAnimNode.cpp @@ -370,7 +370,7 @@ bool CTrackViewAnimNode::IsBoundToEditorObjects() const else { // check if bound to legacy entity - return (m_animNode->GetNodeOwner() != NULL); + return (m_animNode->GetNodeOwner() != nullptr); } } @@ -1468,7 +1468,7 @@ bool CTrackViewAnimNode::PasteNodesFromClipboard(QWidget* context) } XmlNodeRef animNodesRoot = clipboard.Get(); - if (animNodesRoot == NULL || strcmp(animNodesRoot->getTag(), "CopyAnimNodesRoot") != 0) + if (animNodesRoot == nullptr || strcmp(animNodesRoot->getTag(), "CopyAnimNodesRoot") != 0) { return false; } diff --git a/Code/Editor/TrackView/TrackViewDialog.cpp b/Code/Editor/TrackView/TrackViewDialog.cpp index 9a35f09911..331daf6730 100644 --- a/Code/Editor/TrackView/TrackViewDialog.cpp +++ b/Code/Editor/TrackView/TrackViewDialog.cpp @@ -130,10 +130,10 @@ const GUID& CTrackViewDialog::GetClassID() ////////////////////////////////////////////////////////////////////////// -CTrackViewDialog* CTrackViewDialog::s_pTrackViewDialog = NULL; +CTrackViewDialog* CTrackViewDialog::s_pTrackViewDialog = nullptr; ////////////////////////////////////////////////////////////////////////// -CTrackViewDialog::CTrackViewDialog(QWidget* pParent /*=NULL*/) +CTrackViewDialog::CTrackViewDialog(QWidget* pParent /*=nullptr*/) : QMainWindow(pParent) { s_pTrackViewDialog = this; @@ -152,7 +152,7 @@ CTrackViewDialog::CTrackViewDialog(QWidget* pParent /*=NULL*/) m_lazyInitDone = false; m_bEditLock = false; - m_pNodeForTracksToolBar = NULL; + m_pNodeForTracksToolBar = nullptr; m_currentToolBarParamTypeId = 0; @@ -181,7 +181,7 @@ CTrackViewDialog::~CTrackViewDialog() m_findDlg->deleteLater(); m_findDlg = nullptr; } - s_pTrackViewDialog = 0; + s_pTrackViewDialog = nullptr; const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager(); CTrackViewSequence* sequence = pSequenceManager->GetSequenceByEntityId(m_currentSequenceEntityId); @@ -210,7 +210,7 @@ void CTrackViewDialog::OnAddEntityNodeMenu() } ////////////////////////////////////////////////////////////////////////// -BOOL CTrackViewDialog::OnInitDialog() +bool CTrackViewDialog::OnInitDialog() { InitToolbar(); InitMenu(); @@ -270,7 +270,7 @@ BOOL CTrackViewDialog::OnInitDialog() QString cursorPosText = QString("0.000(%1fps)").arg(FloatToIntRet(m_wndCurveEditor->GetFPS())); m_cursorPos->setText(cursorPosText); - return TRUE; // return TRUE unless you set the focus to a control + return true; // return true unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } @@ -621,7 +621,7 @@ void CTrackViewDialog::InitToolbar() { qaction2->setCheckable(true); } - + m_actions[ID_TV_SNAP_NONE]->setChecked(true); m_tracksToolBar = addToolBar("Tracks Toolbar"); @@ -883,7 +883,7 @@ void CTrackViewDialog::Update() // The active camera node means two conditions: // 1. Sequence camera is currently active. // 2. The camera which owns this node has been set as the current camera by the director node. - bool bSequenceCamInUse = gEnv->pMovieSystem->GetCallback() == NULL || + bool bSequenceCamInUse = gEnv->pMovieSystem->GetCallback() == nullptr || gEnv->pMovieSystem->GetCallback()->IsSequenceCamUsed(); AZ::EntityId camId = gEnv->pMovieSystem->GetCameraParams().cameraEntityId; if (camId.IsValid() && bSequenceCamInUse) @@ -2049,7 +2049,7 @@ void CTrackViewDialog::ClearTracksToolBar() m_tracksToolBar->clear(); m_tracksToolBar->addWidget(new QLabel("Tracks:")); - m_pNodeForTracksToolBar = NULL; + m_pNodeForTracksToolBar = nullptr; m_toolBarParamTypes.clear(); m_currentToolBarParamTypeId = 0; } diff --git a/Code/Editor/TrackView/TrackViewDialog.h b/Code/Editor/TrackView/TrackViewDialog.h index f30d9a414f..f6c1126713 100644 --- a/Code/Editor/TrackView/TrackViewDialog.h +++ b/Code/Editor/TrackView/TrackViewDialog.h @@ -52,7 +52,7 @@ class CTrackViewDialog public: friend CMovieCallback; - CTrackViewDialog(QWidget* pParent = NULL); + CTrackViewDialog(QWidget* pParent = nullptr); ~CTrackViewDialog(); static void RegisterViewClass(); @@ -183,7 +183,7 @@ private: void OnAddEntityNodeMenu(); void OnEditorNotifyEvent(EEditorNotifyEvent event) override; - BOOL OnInitDialog(); + bool OnInitDialog(); void SaveLayouts(); void SaveMiscSettings() const; diff --git a/Code/Editor/TrackView/TrackViewDopeSheetBase.cpp b/Code/Editor/TrackView/TrackViewDopeSheetBase.cpp index 34ca2f062f..accba34422 100644 --- a/Code/Editor/TrackView/TrackViewDopeSheetBase.cpp +++ b/Code/Editor/TrackView/TrackViewDopeSheetBase.cpp @@ -88,7 +88,7 @@ CTrackViewDopeSheetBase::CTrackViewDopeSheetBase(QWidget* parent) m_currentTime = 0.0f; m_storedTime = m_currentTime; m_rcSelect = QRect(0, 0, 0, 0); - m_rubberBand = 0; + m_rubberBand = nullptr; m_scrollBar = new QScrollBar(Qt::Horizontal, this); connect(m_scrollBar, &QScrollBar::valueChanged, this, &CTrackViewDopeSheetBase::OnHScroll); m_keyTimeOffset = 0; @@ -113,7 +113,7 @@ CTrackViewDopeSheetBase::CTrackViewDopeSheetBase(QWidget* parent) m_bFastRedraw = false; - m_pLastTrackSelectedOnSpot = NULL; + m_pLastTrackSelectedOnSpot = nullptr; m_wndPropsOnSpot = nullptr; @@ -544,7 +544,7 @@ void CTrackViewDopeSheetBase::OnLButtonUp(Qt::KeyboardModifiers modifiers, const SelectKeys(m_rcSelect, modifiers & Qt::ControlModifier); m_rcSelect = QRect(); m_rubberBand->deleteLater(); - m_rubberBand = 0; + m_rubberBand = nullptr; } else if (m_mouseMode == eTVMouseMode_SelectWithinTime) { @@ -552,7 +552,7 @@ void CTrackViewDopeSheetBase::OnLButtonUp(Qt::KeyboardModifiers modifiers, const SelectAllKeysWithinTimeFrame(m_rcSelect, modifiers & Qt::ControlModifier); m_rcSelect = QRect(); m_rubberBand->deleteLater(); - m_rubberBand = 0; + m_rubberBand = nullptr; } else if (m_mouseMode == eTVMouseMode_DragTime) { @@ -744,7 +744,7 @@ void CTrackViewDopeSheetBase::OnRButtonDown(Qt::KeyboardModifiers modifiers, con } else { - m_pLastTrackSelectedOnSpot = NULL; + m_pLastTrackSelectedOnSpot = nullptr; } ShowKeyPropertyCtrlOnSpot(p.x(), p.y(), selectedKeys.GetKeyCount() > 1, bKeyChangeInSameTrack); @@ -783,7 +783,7 @@ void CTrackViewDopeSheetBase::OnRButtonUp([[maybe_unused]] Qt::KeyboardModifiers if (!m_bCursorWasInKey) { - const bool bHasCopiedKey = (GetKeysInClickboard() != NULL); + const bool bHasCopiedKey = (GetKeysInClickboard() != nullptr); if (bHasCopiedKey && m_bMouseMovedAfterRButtonDown == false) // Once moved, it means the user wanted to scroll, so no paste pop-up. { @@ -1230,24 +1230,24 @@ XmlNodeRef CTrackViewDopeSheetBase::GetKeysInClickboard() CClipboard clip(this); if (clip.IsEmpty()) { - return NULL; + return nullptr; } if (clip.GetTitle() != "Track view keys") { - return NULL; + return nullptr; } XmlNodeRef copyNode = clip.Get(); - if (copyNode == NULL || strcmp(copyNode->getTag(), "CopyKeysNode")) + if (copyNode == nullptr || strcmp(copyNode->getTag(), "CopyKeysNode")) { - return NULL; + return nullptr; } int nNumTracksToPaste = copyNode->getChildCount(); if (nNumTracksToPaste == 0) { - return NULL; + return nullptr; } return copyNode; @@ -1789,7 +1789,7 @@ float CTrackViewDopeSheetBase::FrameSnap(float time) const ////////////////////////////////////////////////////////////////////////// void CTrackViewDopeSheetBase::ShowKeyPropertyCtrlOnSpot(int x, int y, [[maybe_unused]] bool bMultipleKeysSelected, bool bKeyChangeInSameTrack) { - if (m_keyPropertiesDlg == NULL) + if (m_keyPropertiesDlg == nullptr) { return; } diff --git a/Code/Editor/TrackView/TrackViewFindDlg.cpp b/Code/Editor/TrackView/TrackViewFindDlg.cpp index 3d6e93fb05..014618a62a 100644 --- a/Code/Editor/TrackView/TrackViewFindDlg.cpp +++ b/Code/Editor/TrackView/TrackViewFindDlg.cpp @@ -24,13 +24,13 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING // CTrackViewFindDlg dialog -CTrackViewFindDlg::CTrackViewFindDlg(const char* title, QWidget* pParent /*=NULL*/) +CTrackViewFindDlg::CTrackViewFindDlg(const char* title, QWidget* pParent /*=nullptr*/) : QDialog(pParent) , ui(new Ui::TrackViewFindDlg) { setWindowTitle(title); - m_tvDlg = 0; + m_tvDlg = nullptr; m_numSeqs = 0; ui->setupUi(this); diff --git a/Code/Editor/TrackView/TrackViewFindDlg.h b/Code/Editor/TrackView/TrackViewFindDlg.h index 65723634e4..8a3239087d 100644 --- a/Code/Editor/TrackView/TrackViewFindDlg.h +++ b/Code/Editor/TrackView/TrackViewFindDlg.h @@ -32,7 +32,7 @@ class CTrackViewFindDlg Q_OBJECT // Construction public: - CTrackViewFindDlg(const char* title = NULL, QWidget* pParent = NULL); // standard constructor + CTrackViewFindDlg(const char* title = nullptr, QWidget* pParent = nullptr); // standard constructor ~CTrackViewFindDlg(); //Functions diff --git a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp index 158052eb2a..6a5c5b6427 100644 --- a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp +++ b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp @@ -328,8 +328,8 @@ bool CTrackViewTrackPropsDlg::OnKeySelectionChange(CTrackViewKeyBundle& selected } else { - ui->PREVNEXT->setEnabled(FALSE); - ui->TIME->setEnabled(FALSE); + ui->PREVNEXT->setEnabled(false); + ui->TIME->setEnabled(false); } return true; } diff --git a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.h b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.h index d4670a95c8..9b9a933b49 100644 --- a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.h +++ b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.h @@ -74,7 +74,7 @@ protected: // Helper functions. ////////////////////////////////////////////////////////////////////////// template - void SyncValue(CSmartVariable& var, T& value, bool bCopyToUI, IVariable* pSrcVar = NULL) + void SyncValue(CSmartVariable& var, T& value, bool bCopyToUI, IVariable* pSrcVar = nullptr) { if (bCopyToUI) { diff --git a/Code/Editor/TrackView/TrackViewNodes.cpp b/Code/Editor/TrackView/TrackViewNodes.cpp index d69c256049..daf99990a8 100644 --- a/Code/Editor/TrackView/TrackViewNodes.cpp +++ b/Code/Editor/TrackView/TrackViewNodes.cpp @@ -69,7 +69,7 @@ public: : QStyledItemDelegate(parent) {} - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override { bool enabled = index.data(CTrackViewNodesCtrl::CRecord::EnableRole).toBool(); QStyleOptionViewItem opt = option; @@ -106,7 +106,7 @@ protected: return Qt::CopyAction | Qt::MoveAction; } - void dragMoveEvent(QDragMoveEvent* event) + void dragMoveEvent(QDragMoveEvent* event) override { CTrackViewNodesCtrl::CRecord* record = (CTrackViewNodesCtrl::CRecord*) itemAt(event->pos()); if (!record) @@ -144,7 +144,7 @@ protected: } } - void dropEvent(QDropEvent* event) + void dropEvent(QDropEvent* event) override { CTrackViewNodesCtrl::CRecord* record = (CTrackViewNodesCtrl::CRecord*) itemAt(event->pos()); if (!record) @@ -200,7 +200,7 @@ protected: } } - void keyPressEvent(QKeyEvent* event) + void keyPressEvent(QKeyEvent* event) override { // HAVE TO INCLUDE CASES FOR THESE IN THE ShortcutOverride handler in ::event() below switch (event->key()) @@ -242,7 +242,7 @@ protected: } - bool focusNextPrevChild([[maybe_unused]] bool next) + bool focusNextPrevChild([[maybe_unused]] bool next) override { return false; // so we get the tab key } @@ -361,7 +361,7 @@ CTrackViewNodesCtrl::CTrackViewNodesCtrl(QWidget* hParentWnd, CTrackViewDialog* , m_pTrackViewDialog(parent) { ui->setupUi(this); - m_pDopeSheet = 0; + m_pDopeSheet = nullptr; m_currentMatchIndex = 0; m_matchCount = 0; @@ -954,7 +954,7 @@ void CTrackViewNodesCtrl::OnSelectionChanged() ////////////////////////////////////////////////////////////////////////// void CTrackViewNodesCtrl::OnNMRclick(QPoint point) { - CRecord* record = 0; + CRecord* record = nullptr; bool isOnAzEntity = false; CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence(); if (!sequence) @@ -1605,7 +1605,7 @@ CTrackViewTrack* CTrackViewNodesCtrl::GetTrackViewTrack(const Export::EntityAnim } } - return 0; + return nullptr; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/TrackView/TrackViewSplineCtrl.cpp b/Code/Editor/TrackView/TrackViewSplineCtrl.cpp index 19c8b2d4c2..c21403d1f5 100644 --- a/Code/Editor/TrackView/TrackViewSplineCtrl.cpp +++ b/Code/Editor/TrackView/TrackViewSplineCtrl.cpp @@ -56,10 +56,10 @@ protected: } } - virtual int GetSize() { return sizeof(*this); } - virtual QString GetDescription() { return "UndoTrackViewSplineCtrl"; }; + int GetSize() override { return sizeof(*this); } + QString GetDescription() override { return "UndoTrackViewSplineCtrl"; }; - virtual void Undo(bool bUndo) + void Undo(bool bUndo) override { CTrackViewSplineCtrl* pCtrl = FindControl(m_pCtrl); if (pCtrl) @@ -103,7 +103,7 @@ protected: } } - virtual void Redo() + void Redo() override { const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager(); CTrackViewSequence* sequence = pSequenceManager->GetSequenceByEntityId(m_sequenceEntityId); @@ -136,7 +136,7 @@ protected: sequence->OnKeySelectionChanged(); } - virtual bool IsSelectionChanged() const + bool IsSelectionChanged() const override { const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager(); CTrackViewSequence* sequence = sequenceManager->GetSequenceByEntityId(m_sequenceEntityId); @@ -151,19 +151,19 @@ protected: } public: - typedef std::list CTrackViewSplineCtrls; + using CTrackViewSplineCtrls = std::list; static CTrackViewSplineCtrl* FindControl(CTrackViewSplineCtrl* pCtrl) { if (!pCtrl) { - return 0; + return nullptr; } auto iter = std::find(s_activeCtrls.begin(), s_activeCtrls.end(), pCtrl); if (iter == s_activeCtrls.end()) { - return 0; + return nullptr; } return *iter; @@ -449,7 +449,7 @@ void CTrackViewSplineCtrl::AddSpline(ISplineInterpolator* pSpline, CTrackViewTra } si.pSpline = pSpline; - si.pDetailSpline = NULL; + si.pDetailSpline = nullptr; m_splines.push_back(si); m_tracks.push_back(pTrack); m_bKeyTimesDirty = true; @@ -896,7 +896,7 @@ bool CTrackViewSplineCtrl::IsUnifiedKeyCurrentlySelected() const { ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline; - if (pSpline == NULL) + if (pSpline == nullptr) { continue; } @@ -960,7 +960,7 @@ void CTrackViewSplineCtrl::mouseReleaseEvent(QMouseEvent* event) if (GetIEditor()->GetAnimation()->GetSequence()) { bool restoreRecordModeToTrue = (m_editMode == TimeMarkerMode && m_stashedRecordModeWhenDraggingTime); - + SplineWidget::mouseReleaseEvent(event); if (restoreRecordModeToTrue) From 1a80d313e58dbef0ac251ddeca40818050fdcbd6 Mon Sep 17 00:00:00 2001 From: Nemerle Date: Thu, 5 Aug 2021 16:49:02 +0200 Subject: [PATCH 03/18] Editor code: tidy up BOOLs,NULLs and overrides pt4. A few 'typedefs' replaced by 'using's This shouldn't have any functional changes at all, just c++17 modernization It's a part 4 of a split #2847 Signed-off-by: Nemerle --- Code/Editor/Undo/Undo.cpp | 24 +++++++------- Code/Editor/Undo/Undo.h | 4 +-- Code/Editor/Util/3DConnexionDriver.cpp | 10 +++--- Code/Editor/Util/DynamicArray2D.cpp | 2 +- Code/Editor/Util/EditorUtils.cpp | 6 ++-- Code/Editor/Util/EditorUtils.h | 12 +++---- Code/Editor/Util/FileChangeMonitor.cpp | 6 ++-- Code/Editor/Util/FileChangeMonitor.h | 2 +- Code/Editor/Util/FileEnum.cpp | 10 +++--- Code/Editor/Util/FileUtil.cpp | 34 ++++++++++---------- Code/Editor/Util/FileUtil.h | 2 +- Code/Editor/Util/FileUtil_impl.h | 4 +-- Code/Editor/Util/GdiUtil.h | 2 +- Code/Editor/Util/IXmlHistoryManager.h | 2 +- Code/Editor/Util/ImageASC.cpp | 28 ++++++++--------- Code/Editor/Util/ImageGif.cpp | 2 +- Code/Editor/Util/ImageTIF.cpp | 12 +++---- Code/Editor/Util/ImageUtil.cpp | 38 +++++++++++------------ Code/Editor/Util/IndexedFiles.cpp | 2 +- Code/Editor/Util/IndexedFiles.h | 2 +- Code/Editor/Util/KDTree.cpp | 24 +++++++------- Code/Editor/Util/Math.h | 2 +- Code/Editor/Util/MemoryBlock.cpp | 8 ++--- Code/Editor/Util/NamedData.cpp | 12 +++---- Code/Editor/Util/PakFile.cpp | 14 ++++----- Code/Editor/Util/PathUtil.cpp | 8 ++--- Code/Editor/Util/PathUtil.h | 12 +++---- Code/Editor/Util/StringHelpers.cpp | 20 ++++++------ Code/Editor/Util/UIEnumerations.cpp | 8 ++--- Code/Editor/Util/Variable.cpp | 10 +++--- Code/Editor/Util/Variable.h | 10 +++--- Code/Editor/Util/VariablePropertyType.cpp | 12 +++---- Code/Editor/Util/XmlHistoryManager.cpp | 34 ++++++++++---------- Code/Editor/Util/XmlHistoryManager.h | 20 ++++++------ Code/Editor/Util/XmlTemplate.cpp | 8 ++--- Code/Editor/Util/bitarray.h | 2 +- 36 files changed, 204 insertions(+), 204 deletions(-) diff --git a/Code/Editor/Undo/Undo.cpp b/Code/Editor/Undo/Undo.cpp index 5b3d2cd73a..6af141b9e7 100644 --- a/Code/Editor/Undo/Undo.cpp +++ b/Code/Editor/Undo/Undo.cpp @@ -34,7 +34,7 @@ public: { m_undoSteps.push_back(step); } - virtual int GetSize() const + int GetSize() const override { int size = 0; for (int i = 0; i < m_undoSteps.size(); i++) @@ -43,18 +43,18 @@ public: } return size; } - virtual bool IsEmpty() const + bool IsEmpty() const override { return m_undoSteps.empty(); } - virtual void Undo(bool bUndo) + void Undo(bool bUndo) override { for (int i = m_undoSteps.size() - 1; i >= 0; i--) { m_undoSteps[i]->Undo(bUndo); } } - virtual void Redo() + void Redo() override { for (int i = 0; i < m_undoSteps.size(); i++) { @@ -113,8 +113,8 @@ CUndoManager::CUndoManager() m_bRecording = false; m_bSuperRecording = false; - m_currentUndo = 0; - m_superUndo = 0; + m_currentUndo = nullptr; + m_superUndo = nullptr; m_assetManagerUndoInterruptor = new AssetManagerUndoInterruptor(); m_suspendCount = 0; @@ -270,7 +270,7 @@ void CUndoManager::Accept(const QString& name) } m_bRecording = false; - m_currentUndo = 0; + m_currentUndo = nullptr; SignalNumUndoRedoToListeners(); @@ -303,7 +303,7 @@ void CUndoManager::Cancel() } delete m_currentUndo; - m_currentUndo = 0; + m_currentUndo = nullptr; //CLogFile::WriteLine( " Cancel OK" ); } @@ -582,7 +582,7 @@ void CUndoManager::SuperAccept(const QString& name) //CLogFile::FormatLine( "Undo Object Accepted (Undo:%d,Redo:%d)",m_undoStack.size(),m_redoStack.size() ); m_bSuperRecording = false; - m_superUndo = 0; + m_superUndo = nullptr; //CLogFile::WriteLine( " SupperAccept OK" ); SignalNumUndoRedoToListeners(); @@ -616,7 +616,7 @@ void CUndoManager::SuperCancel() m_bSuperRecording = false; delete m_superUndo; - m_superUndo = 0; + m_superUndo = nullptr; //CLogFile::WriteLine( " SuperCancel OK" ); } @@ -708,8 +708,8 @@ void CUndoManager::Flush() delete m_superUndo; delete m_currentUndo; - m_superUndo = 0; - m_currentUndo = 0; + m_superUndo = nullptr; + m_currentUndo = nullptr; SignalUndoFlushedToListeners(); } diff --git a/Code/Editor/Undo/Undo.h b/Code/Editor/Undo/Undo.h index 3f943f7a82..e7b6c5b852 100644 --- a/Code/Editor/Undo/Undo.h +++ b/Code/Editor/Undo/Undo.h @@ -116,7 +116,7 @@ public: continue; } - if (m_undoObjects[i]->GetObjectName() == NULL) + if (m_undoObjects[i]->GetObjectName() == nullptr) { continue; } @@ -209,7 +209,7 @@ public: bool IsHaveUndo() const; bool IsHaveRedo() const; - + void SetMaxUndoStep(int steps); int GetMaxUndoStep() const; diff --git a/Code/Editor/Util/3DConnexionDriver.cpp b/Code/Editor/Util/3DConnexionDriver.cpp index 26f45a4912..c1c3b47c4b 100644 --- a/Code/Editor/Util/3DConnexionDriver.cpp +++ b/Code/Editor/Util/3DConnexionDriver.cpp @@ -34,12 +34,12 @@ bool C3DConnexionDriver::InitDevice() // Find the Raw Devices UINT nDevices; // Get Number of devices attached - if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) + if (GetRawInputDeviceList(nullptr, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { return false; } // Create list large enough to hold all RAWINPUTDEVICE structs - if ((m_pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == NULL) + if ((m_pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == nullptr) { return false; } @@ -85,7 +85,7 @@ bool C3DConnexionDriver::InitDevice() m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsagePage = phidInfo->usUsagePage; m_pRawInputDevices[m_nUsagePage1Usage8Devices].usUsage = phidInfo->usUsage; m_pRawInputDevices[m_nUsagePage1Usage8Devices].dwFlags = 0; - m_pRawInputDevices[m_nUsagePage1Usage8Devices].hwndTarget = NULL; + m_pRawInputDevices[m_nUsagePage1Usage8Devices].hwndTarget = nullptr; m_nUsagePage1Usage8Devices++; } } @@ -126,8 +126,8 @@ bool C3DConnexionDriver::GetInputMessageData(LPARAM lParam, S3DConnexionMessage& { if (event->header.dwType == RIM_TYPEHID) { - static BOOL bGotTranslation = FALSE, - bGotRotation = FALSE; + static bool bGotTranslation = false, + bGotRotation = false; static int all6DOFs[6] = {0}; LPRAWHID pRawHid = &event->data.hid; diff --git a/Code/Editor/Util/DynamicArray2D.cpp b/Code/Editor/Util/DynamicArray2D.cpp index 6d9b1683f2..6ac3edbb6b 100644 --- a/Code/Editor/Util/DynamicArray2D.cpp +++ b/Code/Editor/Util/DynamicArray2D.cpp @@ -58,7 +58,7 @@ CDynamicArray2D::~CDynamicArray2D() } delete [] m_Array; - m_Array = 0; + m_Array = nullptr; } diff --git a/Code/Editor/Util/EditorUtils.cpp b/Code/Editor/Util/EditorUtils.cpp index 8f56e4d956..33c311ed76 100644 --- a/Code/Editor/Util/EditorUtils.cpp +++ b/Code/Editor/Util/EditorUtils.cpp @@ -42,14 +42,14 @@ void HeapCheck::Check([[maybe_unused]] const char* file, [[maybe_unused]] int li { CString str; str.Format( "Bad Start of Heap, at file %s line:%d",file,line ); - MessageBox( NULL,str,"Heap Check",MB_OK ); + MessageBox( nullptr,str,"Heap Check",MB_OK ); } break; case _HEAPBADNODE: { CString str; str.Format( "Bad Node in Heap, at file %s line:%d",file,line ); - MessageBox( NULL,str,"Heap Check",MB_OK ); + MessageBox( nullptr,str,"Heap Check",MB_OK ); } break; } @@ -258,7 +258,7 @@ namespace EditorUtils AzWarningAbsorber::AzWarningAbsorber(const char* window) : m_window(window) AZ_POP_DISABLE_WARNING - { + { BusConnect(); } diff --git a/Code/Editor/Util/EditorUtils.h b/Code/Editor/Util/EditorUtils.h index fb767c98b3..355a1939c2 100644 --- a/Code/Editor/Util/EditorUtils.h +++ b/Code/Editor/Util/EditorUtils.h @@ -359,7 +359,7 @@ inline QString TokenizeString(const QString& s, LPCSTR pszTokens, int& iStart) QByteArray str = s.toUtf8(); - if (pszTokens == NULL) + if (pszTokens == nullptr) { return str; } @@ -472,7 +472,7 @@ inline const char* strstri(const char* pString, const char* pSubstring) } } - return NULL; + return nullptr; } @@ -542,7 +542,7 @@ public: // There is a bug in QT with writing files larger than 32MB. It separates // the write into 32MB blocks, but doesn't write the last block correctly. // To deal with this, we'll separate into blocks here so QT doesn't have to. - + // QT bug in qfileengine_win.cpp line 434. Block size is calculated once and always // used as the amount of data to write, but for the last block, unless there is exactly // block size left to write, the actual remaining amount needs to be written, not the @@ -658,14 +658,14 @@ inline CArchive& operator>>(CArchive& ar, QString& str) str = QString::fromUtf16(reinterpret_cast(raw), aznumeric_cast(length)); } } - + return ar; } inline CArchive& operator<<(CArchive& ar, const QString& str) { // This is written to mimic how MFC archiving worked, which was to - // write markers to indicate the size of the length - + // write markers to indicate the size of the length - // so a length that will fit into 8 bits takes 8 bits. // A length that requires more than 8 bits, puts an 8 bit marker (0xff) // to indicate that the length is greater, then 16 bits for the length. @@ -693,7 +693,7 @@ inline CArchive& operator<<(CArchive& ar, const QString& str) ar << static_cast(0xffff); ar << static_cast(length); } - + ar.device()->write(data); return ar; diff --git a/Code/Editor/Util/FileChangeMonitor.cpp b/Code/Editor/Util/FileChangeMonitor.cpp index c2448e5dac..8a1f961bb0 100644 --- a/Code/Editor/Util/FileChangeMonitor.cpp +++ b/Code/Editor/Util/FileChangeMonitor.cpp @@ -16,7 +16,7 @@ #include -CFileChangeMonitor* CFileChangeMonitor::s_pFileMonitorInstance = NULL; +CFileChangeMonitor* CFileChangeMonitor::s_pFileMonitorInstance = nullptr; ////////////////////////////////////////////////////////////////////////// CFileChangeMonitor::CFileChangeMonitor(QObject* parent) @@ -34,7 +34,7 @@ CFileChangeMonitor::~CFileChangeMonitor() if (pListener) { - pListener->SetMonitor(NULL); + pListener->SetMonitor(nullptr); } } @@ -143,7 +143,7 @@ void CFileChangeMonitor::Unsubscribe(CFileChangeMonitorListener* pListener) { assert(pListener); m_listeners.erase(pListener); - pListener->SetMonitor(NULL); + pListener->SetMonitor(nullptr); } void CFileChangeMonitor::OnDirectoryChange(const QString &path) diff --git a/Code/Editor/Util/FileChangeMonitor.h b/Code/Editor/Util/FileChangeMonitor.h index c2746dc30a..b32686bec4 100644 --- a/Code/Editor/Util/FileChangeMonitor.h +++ b/Code/Editor/Util/FileChangeMonitor.h @@ -111,7 +111,7 @@ class CFileChangeMonitorListener { public: CFileChangeMonitorListener() - : m_pMonitor(NULL) + : m_pMonitor(nullptr) { } diff --git a/Code/Editor/Util/FileEnum.cpp b/Code/Editor/Util/FileEnum.cpp index 1d13929889..98ff0f7f4e 100644 --- a/Code/Editor/Util/FileEnum.cpp +++ b/Code/Editor/Util/FileEnum.cpp @@ -12,7 +12,7 @@ #include "FileEnum.h" CFileEnum::CFileEnum() - : m_hEnumFile(0) + : m_hEnumFile(nullptr) { } @@ -21,7 +21,7 @@ CFileEnum::~CFileEnum() if (m_hEnumFile) { delete m_hEnumFile; - m_hEnumFile = 0; + m_hEnumFile = nullptr; } } @@ -53,7 +53,7 @@ bool CFileEnum::StartEnumeration(const QString& szEnumPathAndPattern, QFileInfo* if (m_hEnumFile) { delete m_hEnumFile; - m_hEnumFile = 0; + m_hEnumFile = nullptr; } QStringList parts = szEnumPathAndPattern.split(QRegularExpression(R"([\\/])")); @@ -66,7 +66,7 @@ bool CFileEnum::StartEnumeration(const QString& szEnumPathAndPattern, QFileInfo* { // No files found delete m_hEnumFile; - m_hEnumFile = 0; + m_hEnumFile = nullptr; return false; } @@ -84,7 +84,7 @@ bool CFileEnum::GetNextFile(QFileInfo* pFile) { // No more files left delete m_hEnumFile; - m_hEnumFile = 0; + m_hEnumFile = nullptr; return false; } diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index 9e4f688f69..32154ec66d 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -279,7 +279,7 @@ void CFileUtil::EditTextureFile(const char* textureFile, [[maybe_unused]] bool b // Qt does. QString fullTexturePathFixedForWindows = QString(fullTexturePath.data()).replace('/', '\\'); QByteArray fullTexturePathFixedForWindowsUtf8 = fullTexturePathFixedForWindows.toUtf8(); - HINSTANCE hInst = ShellExecute(NULL, "open", textureEditorPath.data(), fullTexturePathFixedForWindowsUtf8.data(), NULL, SW_SHOWNORMAL); + HINSTANCE hInst = ShellExecute(nullptr, "open", textureEditorPath.data(), fullTexturePathFixedForWindowsUtf8.data(), nullptr, SW_SHOWNORMAL); failedToLaunch = ((DWORD_PTR)hInst <= 32); #elif defined(AZ_PLATFORM_MAC) failedToLaunch = QProcess::execute(QString("/usr/bin/open"), {"-a", gSettings.textureEditor, QString(fullTexturePath.data()) }) != 0; @@ -332,7 +332,7 @@ bool CFileUtil::EditMayaFile(const char* filepath, const bool bExtractFromPak, c CryMessageBox("Can't open the file. You can specify a source editor in Sandbox Preferences or create an association in Windows.", "Cannot open file!", MB_OK | MB_ICONERROR); } } - return TRUE; + return true; } ////////////////////////////////////////////////////////////////////////// @@ -348,10 +348,10 @@ bool CFileUtil::EditFile(const char* filePath, const bool bExtrackFromPak, const else if ((extension.compare(".bspace") == 0) || (extension.compare(".comb") == 0)) { EditTextFile(filePath, 0, IFileUtil::FILE_TYPE_BSPACE); - return TRUE; + return true; } - return FALSE; + return false; } ////////////////////////////////////////////////////////////////////////// @@ -374,7 +374,7 @@ bool CFileUtil::CalculateDccFilename(const QString& assetFilename, QString& dccF ////////////////////////////////////////////////////////////////////////// bool CFileUtil::ExtractDccFilenameFromAssetDatabase(const QString& assetFilename, QString& dccFilename) { - IAssetItemDatabase* pCurrentDatabaseInterface = NULL; + IAssetItemDatabase* pCurrentDatabaseInterface = nullptr; std::vector assetDatabasePlugins; IEditorClassFactory* pClassFactory = GetIEditor()->GetClassFactory(); pClassFactory->GetClassesByCategory("Asset Item DB", assetDatabasePlugins); @@ -592,7 +592,7 @@ inline bool ScanDirectoryFiles(const QString& root, const QString& path, const Q /* CFileFind finder; - BOOL bWorking = finder.FindFile( Path::Make(dir,fileSpec) ); + bool bWorking = finder.FindFile( Path::Make(dir,fileSpec) ); while (bWorking) { bWorking = finder.FindNextFile(); @@ -663,7 +663,7 @@ inline int ScanDirectoryRecursive(const QString& root, const QString& path, cons { /* CFileFind finder; - BOOL bWorking = finder.FindFile( Path::Make(dir,"*.*") ); + bool bWorking = finder.FindFile( Path::Make(dir,"*.*") ); while (bWorking) { bWorking = finder.FindNextFile(); @@ -847,12 +847,12 @@ void BlockAndWait(const bool& opComplete, QWidget* parent, const char* message) { // note that 16ms below is not the amount of time to wait, its the maximum time that // processEvents is allowed to keep processing them if they just keep being emitted. - // adding a maximum time here means that we get an opportunity to pump the TickBus + // adding a maximum time here means that we get an opportunity to pump the TickBus // periodically even during a flood of events. QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 16); AZ::TickBus::ExecuteQueuedEvents(); } - + // if we are not the main thread then the above will be done by the main thread, and we can just wait for it to happen. // its fairly important we don't sleep for really long because this legacy code is often invoked in a blocking loop // for many items, and in the worst case, any time we spend sleeping here will be added to each item. @@ -1206,10 +1206,10 @@ bool CFileUtil::CreatePath(const QString& strPath) QString strFilename; QString strExtension; QString strCurrentDirectoryPath; - QStringList cstrDirectoryQueue; + QStringList cstrDirectoryQueue; size_t nCurrentPathQueue(0); size_t nTotalPathQueueElements(0); - BOOL bnLastDirectoryWasCreated(FALSE); + bool bnLastDirectoryWasCreated(false); if (PathExists(strPath)) { @@ -1361,7 +1361,7 @@ IFileUtil::ECopyTreeResult CFileUtil::CopyTree(const QString& strSourceDirectory nTotal = cFiles.size(); for (nCurrent = 0; nCurrent < nTotal; ++nCurrent) { - BOOL bnLastFileWasCopied(FALSE); + bool bnLastFileWasCopied(false); if (eCopyResult == IFileUtil::ETREECOPYUSERCANCELED) @@ -1447,7 +1447,7 @@ IFileUtil::ECopyTreeResult CFileUtil::CopyTree(const QString& strSourceDirectory return eCopyResult; } - BOOL bnLastDirectoryWasCreated(FALSE); + bool bnLastDirectoryWasCreated(false); QString sourceName = sourceDir.absoluteFilePath(cDirectories[nCurrent]); QString targetName = targetDir.absoluteFilePath(cDirectories[nCurrent]); @@ -1529,7 +1529,7 @@ IFileUtil::ECopyTreeResult CFileUtil::CopyFile(const QString& strSourceFile, c CUserOptions oFileOptions; IFileUtil::ECopyTreeResult eCopyResult(IFileUtil::ETREECOPYOK); - BOOL bnLastFileWasCopied(FALSE); + bool bnLastFileWasCopied(false); QString name(strSourceFile); QString strQueryFilename; QString strFullStargetName; @@ -1658,7 +1658,7 @@ IFileUtil::ECopyTreeResult CFileUtil::CopyFile(const QString& strSourceFile, c } if (pfnProgress) { - pfnProgress(source.size(), totalRead, 0, 0, 0, 0, 0, 0, 0); + pfnProgress(source.size(), totalRead, 0, 0, 0, 0, nullptr, nullptr, nullptr); } } if (totalRead != source.size()) @@ -1742,7 +1742,7 @@ IFileUtil::ECopyTreeResult CFileUtil::MoveTree(const QString& strSourceDirecto return eCopyResult; } - BOOL bnLastFileWasCopied(FALSE); + bool bnLastFileWasCopied(false); QString sourceName(sourceDir.absoluteFilePath(cFiles[nCurrent])); QString targetName(targetDir.absoluteFilePath(cFiles[nCurrent])); @@ -1816,7 +1816,7 @@ IFileUtil::ECopyTreeResult CFileUtil::MoveTree(const QString& strSourceDirecto nTotal = cDirectories.size(); for (nCurrent = 0; nCurrent < nTotal; ++nCurrent) { - BOOL bnLastDirectoryWasCreated(FALSE); + bool bnLastDirectoryWasCreated(false); if (eCopyResult == IFileUtil::ETREECOPYUSERCANCELED) { diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 000215e98d..210d702f71 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -123,7 +123,7 @@ public: ////////////////////////////////////////////////////////////////////////// // @param LPPROGRESS_ROUTINE pfnProgress - called by the system to notify of file copy progress - // @param LPBOOL pbCancel - when the contents of this BOOL are set to TRUE, the system cancels the copy operation + // @param LPBOOL pbCancel - when the contents of this BOOL are set to true, the system cancels the copy operation static IFileUtil::ECopyTreeResult CopyFile(const QString& strSourceFile, const QString& strTargetFile, bool boConfirmOverwrite = false, ProgressRoutine pfnProgress = nullptr, bool* pbCancel = nullptr); diff --git a/Code/Editor/Util/FileUtil_impl.h b/Code/Editor/Util/FileUtil_impl.h index 2f2872ff6f..04d9e829b9 100644 --- a/Code/Editor/Util/FileUtil_impl.h +++ b/Code/Editor/Util/FileUtil_impl.h @@ -110,8 +110,8 @@ public: ////////////////////////////////////////////////////////////////////////// // @param LPPROGRESS_ROUTINE pfnProgress - called by the system to notify of file copy progress - // @param LPBOOL pbCancel - when the contents of this BOOL are set to TRUE, the system cancels the copy operation - ECopyTreeResult CopyFile(const QString& strSourceFile, const QString& strTargetFile, bool boConfirmOverwrite = false, ProgressRoutine pfnProgress = NULL, bool* pbCancel = NULL) override; + // @param LPBOOL pbCancel - when the contents of this BOOL are set to true, the system cancels the copy operation + ECopyTreeResult CopyFile(const QString& strSourceFile, const QString& strTargetFile, bool boConfirmOverwrite = false, ProgressRoutine pfnProgress = nullptr, bool* pbCancel = nullptr) override; // As we don't have a FileUtil interface here, we have to duplicate some code :-( in order to keep // function calls clean. diff --git a/Code/Editor/Util/GdiUtil.h b/Code/Editor/Util/GdiUtil.h index f61781f7d4..55165b5799 100644 --- a/Code/Editor/Util/GdiUtil.h +++ b/Code/Editor/Util/GdiUtil.h @@ -35,7 +35,7 @@ public: ~CAlphaBitmap(); //! creates the bitmap from raw 32bpp data - //! \param pData the 32bpp raw image data, RGBA, can be NULL and it would create just an empty bitmap + //! \param pData the 32bpp raw image data, RGBA, can be nullptr and it would create just an empty bitmap //! \param aWidth the bitmap width //! \param aHeight the bitmap height bool Create(void* pData, UINT aWidth, UINT aHeight, bool bVerticalFlip = false, bool bPremultiplyAlpha = false); diff --git a/Code/Editor/Util/IXmlHistoryManager.h b/Code/Editor/Util/IXmlHistoryManager.h index 78d849df7d..20f9dd4573 100644 --- a/Code/Editor/Util/IXmlHistoryManager.h +++ b/Code/Editor/Util/IXmlHistoryManager.h @@ -37,7 +37,7 @@ struct IXmlHistoryEventListener eHET_HistoryGroupAdded, eHET_HistoryGroupRemoved, }; - virtual void OnEvent(EHistoryEventType event, void* pData = NULL) = 0; + virtual void OnEvent(EHistoryEventType event, void* pData = nullptr) = 0; }; struct IXmlHistoryView diff --git a/Code/Editor/Util/ImageASC.cpp b/Code/Editor/Util/ImageASC.cpp index 69a6892c65..c018018196 100644 --- a/Code/Editor/Util/ImageASC.cpp +++ b/Code/Editor/Util/ImageASC.cpp @@ -105,34 +105,34 @@ bool CImageASC::Load(const QString& fileName, CFloatImage& image) // ncols = grid width validData = validData && (azstricmp(token, "ncols") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); width = atoi(token); // nrows = grid height - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); validData = validData && (azstricmp(token, "nrows") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); height = atoi(token); // xllcorner = leftmost coordinate. (Skip, we don't care about it) - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); validData = validData && (azstricmp(token, "xllcorner") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); // yllcorner = bottommost coordinate. (Skip, we don't care about it) - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); validData = validData && (azstricmp(token, "yllcorner") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); // cellsize = size of each grid cell. (Skip, we don't care about it) - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); validData = validData && (azstricmp(token, "cellsize") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); // nodata_value = the value used for missing data. We'll replace these with 0 height. - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); validData = validData && (azstricmp(token, "nodata_value") == 0); - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); nodataValue = atof(token); if (!validData) @@ -152,10 +152,10 @@ bool CImageASC::Load(const QString& fileName, CFloatImage& image) int i = 0; float pixelValue; float maxPixel = 0.0f; - while (token != NULL && i < size) + while (token != nullptr && i < size) { - token = azstrtok(NULL, 0, seps, &nextToken); - if (token != NULL) + token = azstrtok(nullptr, 0, seps, &nextToken); + if (token != nullptr) { // Negative heights aren't supported, clamp to 0. pixelValue = max(0.0, atof(token)); diff --git a/Code/Editor/Util/ImageGif.cpp b/Code/Editor/Util/ImageGif.cpp index a0cd6c5650..2c07fc9acb 100644 --- a/Code/Editor/Util/ImageGif.cpp +++ b/Code/Editor/Util/ImageGif.cpp @@ -223,7 +223,7 @@ bool CImageGif::Load(const QString& fileName, CImageEx& outImage) Pass = 0; OutCount = 0; - Palette = NULL; + Palette = nullptr; CHK (Raster = new uint8 [filesize]); if (strncmp((char*) ptr, id87, 6)) diff --git a/Code/Editor/Util/ImageTIF.cpp b/Code/Editor/Util/ImageTIF.cpp index 9040306a44..c4f21855a4 100644 --- a/Code/Editor/Util/ImageTIF.cpp +++ b/Code/Editor/Util/ImageTIF.cpp @@ -142,7 +142,7 @@ bool CImageTIF::Load(const QString& fileName, CImageEx& outImage) uint32 dwWidth, dwHeight; size_t npixels; uint32* raster; - char* dccfilename = NULL; + char* dccfilename = nullptr; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &dwWidth); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &dwHeight); @@ -232,7 +232,7 @@ bool CImageTIF::Load(const QString& fileName, CFloatImage& outImage) { uint32 width = 0, height = 0; uint16 spp = 0, bpp = 0, format = 0; - char* dccfilename = NULL; + char* dccfilename = nullptr; TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &dccfilename); @@ -252,11 +252,11 @@ bool CImageTIF::Load(const QString& fileName, CFloatImage& outImage) // Check to see if it's a GeoTIFF, and if so, whether or not it has the ZScale parameter. uint32 tagCount = 0; - double *pixelScales = NULL; + double *pixelScales = nullptr; if (TIFFGetField(tif, GEOTIFF_MODELPIXELSCALE_TAG, &tagCount, &pixelScales) == 1) { // if there's an xyz scale, and the Z scale isn't 0, let's use it. - if ((tagCount == 3) && (pixelScales != NULL) && (pixelScales[2] != 0.0f)) + if ((tagCount == 3) && (pixelScales != nullptr) && (pixelScales[2] != 0.0f)) { pixelValueScale = static_cast(pixelScales[2]); } @@ -455,7 +455,7 @@ const char* CImageTIF::GetPreset(const QString& fileName) if (!file.Open(fileName.toUtf8().data(), "rb")) { CLogFile::FormatLine("File not found %s", fileName.toUtf8().data()); - return NULL; + return nullptr; } MemImage memImage; @@ -473,7 +473,7 @@ const char* CImageTIF::GetPreset(const QString& fileName) libtiffDummyCloseProc, libtiffDummySizeProc, libtiffDummyMapFileProc, libtiffDummyUnmapFileProc); string strReturn; - char* preset = NULL; + char* preset = nullptr; int size; if (tif) { diff --git a/Code/Editor/Util/ImageUtil.cpp b/Code/Editor/Util/ImageUtil.cpp index 1b985c82f9..3d121a1d47 100644 --- a/Code/Editor/Util/ImageUtil.cpp +++ b/Code/Editor/Util/ImageUtil.cpp @@ -149,13 +149,13 @@ bool CImageUtil::LoadPGM(const QString& fileName, CImageEx& image) char* nextToken = nullptr; token = azstrtok(str, 0, seps, &nextToken); - while (token != NULL && token[0] == '#') + while (token != nullptr && token[0] == '#') { - if (token != NULL && token[0] == '#') + if (token != nullptr && token[0] == '#') { - azstrtok(NULL, 0, "\n", &nextToken); + azstrtok(nullptr, 0, "\n", &nextToken); } - token = azstrtok(NULL, 0, seps, &nextToken); + token = azstrtok(nullptr, 0, seps, &nextToken); } if (azstricmp(token, "P2") != 0) { @@ -167,32 +167,32 @@ bool CImageUtil::LoadPGM(const QString& fileName, CImageEx& image) do { - token = azstrtok(NULL, 0, seps, &nextToken); - if (token != NULL && token[0] == '#') + token = azstrtok(nullptr, 0, seps, &nextToken); + if (token != nullptr && token[0] == '#') { - azstrtok(NULL, 0, "\n", &nextToken); + azstrtok(nullptr, 0, "\n", &nextToken); } - } while (token != NULL && token[0] == '#'); + } while (token != nullptr && token[0] == '#'); width = atoi(token); do { - token = azstrtok(NULL, 0, seps, &nextToken); - if (token != NULL && token[0] == '#') + token = azstrtok(nullptr, 0, seps, &nextToken); + if (token != nullptr && token[0] == '#') { - azstrtok(NULL, 0, "\n", &nextToken); + azstrtok(nullptr, 0, "\n", &nextToken); } - } while (token != NULL && token[0] == '#'); + } while (token != nullptr && token[0] == '#'); height = atoi(token); do { - token = azstrtok(NULL, 0, seps, &nextToken); - if (token != NULL && token[0] == '#') + token = azstrtok(nullptr, 0, seps, &nextToken); + if (token != nullptr && token[0] == '#') { - azstrtok(NULL, 0, "\n", &nextToken); + azstrtok(nullptr, 0, "\n", &nextToken); } - } while (token != NULL && token[0] == '#'); + } while (token != nullptr && token[0] == '#'); numColors = atoi(token); image.Allocate(width, height); @@ -200,12 +200,12 @@ bool CImageUtil::LoadPGM(const QString& fileName, CImageEx& image) uint32* p = image.GetData(); int size = width * height; int i = 0; - while (token != NULL && i < size) + while (token != nullptr && i < size) { do { - token = azstrtok(NULL, 0, seps, &nextToken); - } while (token != NULL && token[0] == '#'); + token = azstrtok(nullptr, 0, seps, &nextToken); + } while (token != nullptr && token[0] == '#'); *p++ = atoi(token); i++; } diff --git a/Code/Editor/Util/IndexedFiles.cpp b/Code/Editor/Util/IndexedFiles.cpp index c90b3c5f20..ae777abb49 100644 --- a/Code/Editor/Util/IndexedFiles.cpp +++ b/Code/Editor/Util/IndexedFiles.cpp @@ -14,7 +14,7 @@ #include "IndexedFiles.h" volatile TIntAtomic CIndexedFiles::s_bIndexingDone; -CIndexedFiles* CIndexedFiles::s_pIndexedFiles = NULL; +CIndexedFiles* CIndexedFiles::s_pIndexedFiles = nullptr; bool CIndexedFiles::m_startedFileIndexing = false; diff --git a/Code/Editor/Util/IndexedFiles.h b/Code/Editor/Util/IndexedFiles.h index 34554dbe37..e23c0ea827 100644 --- a/Code/Editor/Util/IndexedFiles.h +++ b/Code/Editor/Util/IndexedFiles.h @@ -88,7 +88,7 @@ public: } public: - void Initialize(const QString& path, IFileUtil::ScanDirectoryUpdateCallBack updateCB = NULL); + void Initialize(const QString& path, IFileUtil::ScanDirectoryUpdateCallBack updateCB = nullptr); // Adds a new file to the database. void AddFile(const IFileUtil::FileDesc& path); diff --git a/Code/Editor/Util/KDTree.cpp b/Code/Editor/Util/KDTree.cpp index c8fe742370..4547149e9b 100644 --- a/Code/Editor/Util/KDTree.cpp +++ b/Code/Editor/Util/KDTree.cpp @@ -17,9 +17,9 @@ class KDTreeNode public: KDTreeNode() { - pChildren[0] = NULL; - pChildren[1] = NULL; - pVertexIndices = NULL; + pChildren[0] = nullptr; + pChildren[1] = nullptr; + pVertexIndices = nullptr; } ~KDTreeNode() { @@ -76,13 +76,13 @@ public: } bool IsLeaf() const { - return pChildren[0] == NULL && pChildren[1] == NULL; + return pChildren[0] == nullptr && pChildren[1] == nullptr; } KDTreeNode* GetChild(uint32 nIndex) const { if (nIndex > 1) { - return NULL; + return nullptr; } return pChildren[nIndex]; } @@ -200,7 +200,7 @@ bool SearchForBestSplitPos(CKDTree::ESplitAxis axis, const std::vectorpStatObj->GetIndexedMesh(); - if (pMesh == NULL) + if (pMesh == nullptr) { continue; } @@ -256,7 +256,7 @@ bool SplitNode(const std::vector& statObjList, const AABB& bo const CKDTree::SStatObj* pObj = &statObjList[nObjIndex]; const IIndexedMesh* pMesh = pObj->pStatObj->GetIndexedMesh(); - if (pMesh == NULL) + if (pMesh == nullptr) { return false; } @@ -295,7 +295,7 @@ bool SplitNode(const std::vector& statObjList, const AABB& bo CKDTree::CKDTree() { - m_pRootNode = NULL; + m_pRootNode = nullptr; } CKDTree::~CKDTree() @@ -308,7 +308,7 @@ CKDTree::~CKDTree() bool CKDTree::Build(IStatObj* pStatObj) { - if (pStatObj == NULL) + if (pStatObj == nullptr) { return false; } @@ -332,7 +332,7 @@ bool CKDTree::Build(IStatObj* pStatObj) for (int i = 0, iStatObjSize(m_StatObjectList.size()); i < iStatObjSize; ++i) { IIndexedMesh* pMesh = m_StatObjectList[i].pStatObj->GetIndexedMesh(true); - if (pMesh == NULL) + if (pMesh == nullptr) { continue; } @@ -398,7 +398,7 @@ void CKDTree::BuildRecursively(KDTreeNode* pNode, const AABB& boundbox, std::vec void CKDTree::ConstructStatObjList(IStatObj* pStatObj, const Matrix34& matParent) { - if (pStatObj == NULL) + if (pStatObj == nullptr) { return; } @@ -472,7 +472,7 @@ bool CKDTree::FindNearestVertexRecursively(KDTreeNode* pNode, const Vec3& raySrc const SStatObj* pStatObjInfo = &(m_StatObjectList[nObjIndex]); IIndexedMesh* pMesh = m_StatObjectList[nObjIndex].pStatObj->GetIndexedMesh(); - if (pMesh == NULL) + if (pMesh == nullptr) { continue; } diff --git a/Code/Editor/Util/Math.h b/Code/Editor/Util/Math.h index 66bbf883e8..34fb77e434 100644 --- a/Code/Editor/Util/Math.h +++ b/Code/Editor/Util/Math.h @@ -128,7 +128,7 @@ inline float PointToLineDistance(const Vec3& p1, const Vec3& p2, const Vec3& p3, @param p2 Target point of first line. @param p3 Source point of second line. @param p4 Target point of second line. - @return FALSE if no solution exists. + @return false if no solution exists. */ inline bool LineLineIntersect(const Vec3& p1, const Vec3& p2, const Vec3& p3, const Vec3& p4, Vec3& pa, Vec3& pb, float& mua, float& mub) diff --git a/Code/Editor/Util/MemoryBlock.cpp b/Code/Editor/Util/MemoryBlock.cpp index 1368553511..03d432762d 100644 --- a/Code/Editor/Util/MemoryBlock.cpp +++ b/Code/Editor/Util/MemoryBlock.cpp @@ -18,7 +18,7 @@ ////////////////////////////////////////////////////////////////////////// CMemoryBlock::CMemoryBlock() - : m_buffer(0) + : m_buffer(nullptr) , m_size(0) , m_uncompressedSize(0) , m_owns(false) @@ -54,7 +54,7 @@ CMemoryBlock& CMemoryBlock::operator=(const CMemoryBlock& mem) } else { - m_buffer = 0; + m_buffer = nullptr; m_size = 0; m_owns = false; } @@ -104,7 +104,7 @@ bool CMemoryBlock::Allocate(int size, int uncompressedSize) m_size = size; m_uncompressedSize = uncompressedSize; // Check if allocation failed. - if (m_buffer == 0) + if (m_buffer == nullptr) { return false; } @@ -118,7 +118,7 @@ void CMemoryBlock::Free() { free(m_buffer); } - m_buffer = 0; + m_buffer = nullptr; m_owns = false; m_size = 0; m_uncompressedSize = 0; diff --git a/Code/Editor/Util/NamedData.cpp b/Code/Editor/Util/NamedData.cpp index 1f0d6c5a50..240d71f58d 100644 --- a/Code/Editor/Util/NamedData.cpp +++ b/Code/Editor/Util/NamedData.cpp @@ -36,7 +36,7 @@ void CNamedData::AddDataBlock(const QString& blockName, void* pData, int nSize assert(pData); assert(nSize > 0); - DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)0); + DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)nullptr); if (pBlock) { delete pBlock; @@ -66,7 +66,7 @@ void CNamedData::AddDataBlock(const QString& blockName, void* pData, int nSize void CNamedData::AddDataBlock(const QString& blockName, CMemoryBlock& mem) { - DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)0); + DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)nullptr); if (pBlock) { delete pBlock; @@ -102,7 +102,7 @@ void CNamedData::Clear() ////////////////////////////////////////////////////////////////////////// bool CNamedData::GetDataBlock(const QString& blockName, void*& pData, int& nSize) { - pData = 0; + pData = nullptr; nSize = 0; bool bUncompressed = false; @@ -119,10 +119,10 @@ bool CNamedData::GetDataBlock(const QString& blockName, void*& pData, int& nSize ////////////////////////////////////////////////////////////////////////// CMemoryBlock* CNamedData::GetDataBlock(const QString& blockName, bool& bCompressed) { - DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)0); + DataBlock* pBlock = stl::find_in_map(m_blocks, blockName, (DataBlock*)nullptr); if (!pBlock) { - return 0; + return nullptr; } if (bCompressed) @@ -150,7 +150,7 @@ CMemoryBlock* CNamedData::GetDataBlock(const QString& blockName, bool& bCompress } } } - return 0; + return nullptr; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/Util/PakFile.cpp b/Code/Editor/Util/PakFile.cpp index 5c26b9a7a2..88d5598495 100644 --- a/Code/Editor/Util/PakFile.cpp +++ b/Code/Editor/Util/PakFile.cpp @@ -21,14 +21,14 @@ ////////////////////////////////////////////////////////////////////////// CPakFile::CPakFile() - : m_pArchive(NULL) - , m_pCryPak(NULL) + : m_pArchive(nullptr) + , m_pCryPak(nullptr) { } ////////////////////////////////////////////////////////////////////////// CPakFile::CPakFile(AZ::IO::IArchive* pCryPak) - : m_pArchive(NULL) + : m_pArchive(nullptr) , m_pCryPak(pCryPak) { } @@ -42,14 +42,14 @@ CPakFile::~CPakFile() ////////////////////////////////////////////////////////////////////////// CPakFile::CPakFile(const char* filename) { - m_pArchive = NULL; + m_pArchive = nullptr; Open(filename); } ////////////////////////////////////////////////////////////////////////// void CPakFile::Close() { - m_pArchive = NULL; + m_pArchive = nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -61,7 +61,7 @@ bool CPakFile::Open(const char* filename, bool bAbsolutePath) } auto pCryPak = m_pCryPak ? m_pCryPak : GetIEditor()->GetSystem()->GetIPak(); - if (pCryPak == NULL) + if (pCryPak == nullptr) { return false; } @@ -89,7 +89,7 @@ bool CPakFile::OpenForRead(const char* filename) Close(); } auto pCryPak = m_pCryPak ? m_pCryPak : GetIEditor()->GetSystem()->GetIPak(); - if (pCryPak == NULL) + if (pCryPak == nullptr) { return false; } diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp index 4bb5c20ece..2be09da06f 100644 --- a/Code/Editor/Util/PathUtil.cpp +++ b/Code/Editor/Util/PathUtil.cpp @@ -42,7 +42,7 @@ namespace Path // Directory named filenames containing ":" are invalid, so we can assume if there is a : // it will be the drive name. pchCurrentPosition = strchr(pchLastPosition, ':'); - if (pchCurrentPosition == NULL) + if (pchCurrentPosition == nullptr) { rstrDriveLetter = ""; } @@ -54,7 +54,7 @@ namespace Path pchCurrentPosition = strrchr(pchLastPosition, '\\'); pchAuxPosition = strrchr(pchLastPosition, '/'); - if ((pchCurrentPosition == NULL) && (pchAuxPosition == NULL)) + if ((pchCurrentPosition == nullptr) && (pchAuxPosition == nullptr)) { rstrDirectory = ""; } @@ -70,7 +70,7 @@ namespace Path } pchCurrentPosition = strrchr(pchLastPosition, '.'); - if (pchCurrentPosition == NULL) + if (pchCurrentPosition == nullptr) { rstrExtension = ""; strFilename.assign(pchLastPosition); @@ -114,7 +114,7 @@ namespace Path do { pchCurrentPosition = strpbrk(pchLastPosition, "\\/"); - if (pchCurrentPosition == NULL) + if (pchCurrentPosition == nullptr) { break; } diff --git a/Code/Editor/Util/PathUtil.h b/Code/Editor/Util/PathUtil.h index 0f87df0d5c..868d9843ab 100644 --- a/Code/Editor/Util/PathUtil.h +++ b/Code/Editor/Util/PathUtil.h @@ -228,7 +228,7 @@ namespace Path { return (path.endsWith(QStringLiteral("\\")) || path.endsWith(QStringLiteral("/"))); } - + template inline bool EndsWithSlash(CryStackStringT* path) { @@ -236,15 +236,15 @@ namespace Path { return false; } - + if ( ((*path)[path->size() - 1] != '\\') || - ((*path)[path->size() - 1] != '/') + ((*path)[path->size() - 1] != '/') ) { return true; } - + return false; } @@ -336,9 +336,9 @@ namespace Path { char path_buffer[_MAX_PATH]; #ifdef AZ_COMPILER_MSVC - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), NULL, dir.toUtf8().data(), filename.toUtf8().data(), ext.toUtf8().data()); + _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), nullptr, dir.toUtf8().data(), filename.toUtf8().data(), ext.toUtf8().data()); #else - _makepath(path_buffer, NULL, dir.toUtf8().data(), filename.toUtf8().data(), ext.toUtf8().data()); + _makepath(path_buffer, nullptr, dir.toUtf8().data(), filename.toUtf8().data(), ext.toUtf8().data()); #endif return CaselessPaths(path_buffer); } diff --git a/Code/Editor/Util/StringHelpers.cpp b/Code/Editor/Util/StringHelpers.cpp index 836090e923..5d37dfef77 100644 --- a/Code/Editor/Util/StringHelpers.cpp +++ b/Code/Editor/Util/StringHelpers.cpp @@ -48,7 +48,7 @@ static inline int Vscprintf(const char* format, va_list argList) int retval; va_list argcopy; va_copy(argcopy, argList); - retval = azvsnprintf(NULL, 0, format, argcopy); + retval = azvsnprintf(nullptr, 0, format, argcopy); va_end(argcopy); return retval; #else @@ -64,7 +64,7 @@ static inline int Vscprintf(const wchar_t* format, va_list argList) int retval; va_list argcopy; va_copy(argcopy, argList); - retval = azvsnwprintf(NULL, 0, format, argcopy); + retval = azvsnwprintf(nullptr, 0, format, argcopy); va_end(argcopy); return retval; #else @@ -408,9 +408,9 @@ bool StringHelpers::MatchesWildcardsIgnoreCase(const wstring& str, const wstring template static inline bool MatchesWildcardsIgnoreCaseExt_Tpl(const TS& str, const TS& wildcards, std::vector& wildcardMatches) { - const typename TS::value_type* savedStrBegin = 0; - const typename TS::value_type* savedStrEnd = 0; - const typename TS::value_type* savedWild = 0; + const typename TS::value_type* savedStrBegin = nullptr; + const typename TS::value_type* savedStrEnd = nullptr; + const typename TS::value_type* savedWild = nullptr; size_t savedWildCount = 0; const typename TS::value_type* pStr = str.c_str(); @@ -775,7 +775,7 @@ void StringHelpers::SplitByAnyOf(const wstring& str, const wstring& separators, template static inline TS FormatVA_Tpl(const typename TS::value_type* const format, va_list parg) { - if ((format == 0) || (format[0] == 0)) + if ((format == nullptr) || (format[0] == 0)) { return TS(); } @@ -935,8 +935,8 @@ static string ConvertUtf16ToMultibyte(const wchar_t* wstr, uint codePage, char b len, 0, 0, - ((badChar && codePage != CP_UTF8) ? &badChar : NULL), - NULL); + ((badChar && codePage != CP_UTF8) ? &badChar : nullptr), + nullptr); if (neededByteCount <= 0) { return string(); @@ -952,8 +952,8 @@ static string ConvertUtf16ToMultibyte(const wchar_t* wstr, uint codePage, char b len, &buffer[0], // output buffer neededByteCount - 1, // size of the output buffer in bytes - ((badChar && codePage != CP_UTF8) ? &badChar : NULL), - NULL); + ((badChar && codePage != CP_UTF8) ? &badChar : nullptr), + nullptr); if (byteCount != neededByteCount - 1) { return string(); diff --git a/Code/Editor/Util/UIEnumerations.cpp b/Code/Editor/Util/UIEnumerations.cpp index 8d9fc40377..2666a49f8e 100644 --- a/Code/Editor/Util/UIEnumerations.cpp +++ b/Code/Editor/Util/UIEnumerations.cpp @@ -55,15 +55,15 @@ CUIEnumerations::TDValuesContainer& CUIEnumerations::GetStandardNameContainer() { oEnumerationItem = oEnumaration->getChild(nCurrentEnumarationItem); - const char* szKey(NULL); - const char* szValue(NULL); + const char* szKey(nullptr); + const char* szValue(nullptr); oEnumerationItem->getAttributeByIndex(0, &szKey, &szValue); cValues.push_back(szValue); } - const char* szKey(NULL); - const char* szValue(NULL); + const char* szKey(nullptr); + const char* szValue(nullptr); oEnumaration->getAttributeByIndex(0, &szKey, &szValue); cValuesContainer.insert(TDValuesContainer::value_type(szValue, cValues)); diff --git a/Code/Editor/Util/Variable.cpp b/Code/Editor/Util/Variable.cpp index 5125032baf..ee5ccc9879 100644 --- a/Code/Editor/Util/Variable.cpp +++ b/Code/Editor/Util/Variable.cpp @@ -447,7 +447,7 @@ void CVarObject::AddVariable(CVariableArray& table, CVariableBase& var, const QS ////////////////////////////////////////////////////////////////////////// void CVarObject::RemoveVariable(IVariable* var) { - if (m_vars != NULL) + if (m_vars != nullptr) { m_vars->DeleteVariable(var); } @@ -455,7 +455,7 @@ void CVarObject::RemoveVariable(IVariable* var) ////////////////////////////////////////////////////////////////////////// void CVarObject::EnableUpdateCallbacks(bool boEnable) { - if (m_vars != NULL) + if (m_vars != nullptr) { m_vars->EnableUpdateCallbacks(boEnable); } @@ -463,7 +463,7 @@ void CVarObject::EnableUpdateCallbacks(bool boEnable) ////////////////////////////////////////////////////////////////////////// void CVarObject::OnSetValues() { - if (m_vars != NULL) + if (m_vars != nullptr) { m_vars->OnSetValues(); } @@ -471,7 +471,7 @@ void CVarObject::OnSetValues() ////////////////////////////////////////////////////////////////////////// void CVarObject::ReserveNumVariables(int numVars) { - if (m_vars != NULL) + if (m_vars != nullptr) { m_vars->ReserveNumVariables(numVars); } @@ -482,7 +482,7 @@ void CVarObject::CopyVariableValues(CVarObject* sourceObject) { // Check if compatible types. assert(metaObject() == sourceObject->metaObject()); - if (m_vars != NULL && sourceObject->m_vars != NULL) + if (m_vars != nullptr && sourceObject->m_vars != nullptr) { m_vars->CopyValues(sourceObject->m_vars); } diff --git a/Code/Editor/Util/Variable.h b/Code/Editor/Util/Variable.h index 0d1e7a9ef1..83afee0924 100644 --- a/Code/Editor/Util/Variable.h +++ b/Code/Editor/Util/Variable.h @@ -1411,7 +1411,7 @@ protected: struct IVarEnumList : public CRefCountBase { - //! Get the name of specified value in enumeration, or NULL if out of range. + //! Get the name of specified value in enumeration, or empty string if out of range. virtual QString GetItemName(uint index) = 0; }; typedef _smart_ptr IVarEnumListPtr; @@ -1498,7 +1498,7 @@ public: { if (index >= m_items.size()) { - return NULL; + return QString(); } return m_items[index].name; }; @@ -1869,9 +1869,9 @@ public: void Serialize(XmlNodeRef node, bool load); CVarBlock* GetVarBlock() const { return m_vars; }; - void AddVariable(CVariableBase& var, const QString& varName, VarOnSetCallback* cb = NULL, unsigned char dataType = IVariable::DT_SIMPLE); - void AddVariable(CVariableBase& var, const QString& varName, const QString& varHumanName, VarOnSetCallback* cb = NULL, unsigned char dataType = IVariable::DT_SIMPLE); - void AddVariable(CVariableArray& table, CVariableBase& var, const QString& varName, const QString& varHumanName, VarOnSetCallback* cb = NULL, unsigned char dataType = IVariable::DT_SIMPLE); + void AddVariable(CVariableBase& var, const QString& varName, VarOnSetCallback* cb = nullptr, unsigned char dataType = IVariable::DT_SIMPLE); + void AddVariable(CVariableBase& var, const QString& varName, const QString& varHumanName, VarOnSetCallback* cb = nullptr, unsigned char dataType = IVariable::DT_SIMPLE); + void AddVariable(CVariableArray& table, CVariableBase& var, const QString& varName, const QString& varHumanName, VarOnSetCallback* cb = nullptr, unsigned char dataType = IVariable::DT_SIMPLE); void ReserveNumVariables(int numVars); void RemoveVariable(IVariable* var); diff --git a/Code/Editor/Util/VariablePropertyType.cpp b/Code/Editor/Util/VariablePropertyType.cpp index c6d26b3470..014995467b 100644 --- a/Code/Editor/Util/VariablePropertyType.cpp +++ b/Code/Editor/Util/VariablePropertyType.cpp @@ -71,28 +71,28 @@ namespace Prop Description::Description() : m_type(ePropertyInvalid) , m_numImages(-1) - , m_enumList(NULL) + , m_enumList(nullptr) , m_rangeMin(0) , m_rangeMax(100) , m_step(0) , m_bHardMin(false) , m_bHardMax(false) , m_valueMultiplier(1) - , m_pEnumDBItem(NULL) + , m_pEnumDBItem(nullptr) { } Description::Description(IVariable* pVar) : m_type(ePropertyInvalid) , m_numImages(-1) - , m_enumList(NULL) + , m_enumList(nullptr) , m_rangeMin(0) , m_rangeMax(100) , m_step(0) , m_bHardMin(false) , m_bHardMax(false) , m_valueMultiplier(1) - , m_pEnumDBItem(NULL) + , m_pEnumDBItem(nullptr) { if (!pVar) { @@ -110,7 +110,7 @@ namespace Prop m_name = pVar->GetHumanName(); m_enumList = pVar->GetEnumList(); - if (m_enumList != NULL) + if (m_enumList != nullptr) { m_type = ePropertySelection; } @@ -325,7 +325,7 @@ namespace Prop case ePropertyAudioPreloadRequest: return "AudioPreloadRequest"; default: - return 0; + return nullptr; } } } diff --git a/Code/Editor/Util/XmlHistoryManager.cpp b/Code/Editor/Util/XmlHistoryManager.cpp index 3aea041d29..ed92700705 100644 --- a/Code/Editor/Util/XmlHistoryManager.cpp +++ b/Code/Editor/Util/XmlHistoryManager.cpp @@ -76,7 +76,7 @@ const XmlNodeRef& SXmlHistory::GetCurrentVersion(bool* bVersionExist, int* iVers bool SXmlHistory::IsModified() const { int currVersion; - GetCurrentVersion(NULL, &currVersion); + GetCurrentVersion(nullptr, &currVersion); return m_SavedVersion != currVersion; } @@ -94,7 +94,7 @@ void SXmlHistory::FlagAsSaved() if (Exist()) { int currVersion; - GetCurrentVersion(NULL, &currVersion); + GetCurrentVersion(nullptr, &currVersion); m_SavedVersion = currVersion; } } @@ -167,7 +167,7 @@ SXmlHistory* SXmlHistoryGroup::GetHistory(int index) const --index; } } - return it != m_List.end() ? *it : NULL; + return it != m_List.end() ? *it : nullptr; } //////////////////////////////////////////////////////////////////////////// @@ -199,7 +199,7 @@ SXmlHistory* SXmlHistoryGroup::GetHistoryByTypeId(uint32 typeId, int index /*= 0 return pHistory; } } - return NULL; + return nullptr; } //////////////////////////////////////////////////////////////////////////// @@ -246,9 +246,9 @@ int SXmlHistoryGroup::GetHistoryIndex(const SXmlHistory* pHistory) const CXmlHistoryManager::CXmlHistoryManager() : m_CurrentVersion(0) , m_LatestVersion(0) - , m_pExclusiveListener(NULL) + , m_pExclusiveListener(nullptr) , m_RecordNextVersion(false) - , m_pExActiveGroup(NULL) + , m_pExActiveGroup(nullptr) , m_bIsActiveGroupEx(false) { m_pNullGroup = new SXmlHistoryGroup(this, (uint32) - 1); @@ -376,7 +376,7 @@ void CXmlHistoryManager::PrepareForNextVersion() } ///////////////////////////////////////////////////////////////////////////// -void CXmlHistoryManager::RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc /*= NULL*/) +void CXmlHistoryManager::RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc /*= nullptr*/) { assert(m_RecordNextVersion); RegisterUndoEventHandler(this, pHistory); @@ -405,7 +405,7 @@ void CXmlHistoryManager::ClearHistory(bool flagAsSaved) it->ClearHistory(flagAsSaved); } - SetActiveGroup(NULL); + SetActiveGroup(nullptr); m_CurrentVersion = 0; m_LatestVersion = 0; @@ -451,14 +451,14 @@ SXmlHistoryGroup* CXmlHistoryManager::CreateXmlGroup(uint32 typeId) } ///////////////////////////////////////////////////////////////////////////// -void CXmlHistoryManager::AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= NULL*/) +void CXmlHistoryManager::AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= nullptr*/) { RecordUndoInternal(undoDesc ? undoDesc : "New XML Group added"); m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups.push_back(pGroup); NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupAdded, (void*)pGroup); } ///////////////////////////////////////////////////////////////////////////// -void CXmlHistoryManager::RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= NULL*/) +void CXmlHistoryManager::RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= nullptr*/) { bool unload = m_HistoryInfoMap[ m_CurrentVersion ].CurrGroup == pGroup; RecordUndoInternal(undoDesc ? undoDesc : "XML Group deleted"); @@ -466,14 +466,14 @@ void CXmlHistoryManager::RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const ch stl::find_and_erase(list, pGroup); if (unload) { - SetActiveGroupInt(NULL); + SetActiveGroupInt(nullptr); } m_HistoryInfoMap[ m_CurrentVersion ].CurrGroup = m_pNullGroup; NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupRemoved, (void*)pGroup); } ///////////////////////////////////////////////////////////////////////////// -void CXmlHistoryManager::SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName /*= NULL*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/, bool setExternal /*= false*/) +void CXmlHistoryManager::SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName /*= nullptr*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/, bool setExternal /*= false*/) { TGroupIndexMap userIndex; const SXmlHistoryGroup* pActiveGroup = GetActiveGroup(userIndex); @@ -488,7 +488,7 @@ void CXmlHistoryManager::SetActiveGroup(const SXmlHistoryGroup* pGroup, const ch } } -void CXmlHistoryManager::SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName /*= NULL*/, bool bRecordNullUndo /*= false*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/) +void CXmlHistoryManager::SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName /*= nullptr*/, bool bRecordNullUndo /*= false*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/) { UnloadInt(); @@ -511,7 +511,7 @@ void CXmlHistoryManager::SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const userIndexCount[ (*history)->GetTypeId() ] = 0; } uint32 userindex = userIndexCount[ (*history)->GetTypeId() ]; - IXmlUndoEventHandler* pEventHandler = NULL; + IXmlUndoEventHandler* pEventHandler = nullptr; TGroupIndexMap::const_iterator indexIter = groupIndex.find((*history)->GetTypeId()); if (indexIter == groupIndex.end() || indexIter->second == userindex) { @@ -581,12 +581,12 @@ const SXmlHistoryGroup* CXmlHistoryManager::GetActiveGroup(TGroupIndexMap& currU if (it != m_HistoryInfoMap.end() && pGroup) { currUserIndex = it->second.CurrUserIndex; - return pGroup == m_pNullGroup ? NULL : pGroup; + return pGroup == m_pNullGroup ? nullptr : pGroup; } } currVersion--; } while (currVersion >= 0); - return NULL; + return nullptr; } ///////////////////////////////////////////////////////////////////////////// @@ -796,7 +796,7 @@ SXmlHistory* CXmlHistoryManager::GetLatestHistory(SUndoEventHandlerData& eventHa } currVersion--; } while (currVersion >= 0); - return NULL; + return nullptr; } diff --git a/Code/Editor/Util/XmlHistoryManager.h b/Code/Editor/Util/XmlHistoryManager.h index d894bc7f00..d7aae71939 100644 --- a/Code/Editor/Util/XmlHistoryManager.h +++ b/Code/Editor/Util/XmlHistoryManager.h @@ -23,9 +23,9 @@ public: void AddToHistory(const XmlNodeRef& newXmlVersion); - const XmlNodeRef& Undo(bool* bVersionExist = NULL); + const XmlNodeRef& Undo(bool* bVersionExist = nullptr); const XmlNodeRef& Redo(); - const XmlNodeRef& GetCurrentVersion(bool* bVersionExist = NULL, int* iVersionNumber = NULL) const; + const XmlNodeRef& GetCurrentVersion(bool* bVersionExist = nullptr, int* iVersionNumber = nullptr) const; bool IsModified() const; uint32 GetTypeId() const {return m_typeId; } void FlagAsDeleted(); @@ -93,7 +93,7 @@ public: void RestoreUndoEventHandler(IXmlUndoEventHandler* pEventHandler, uint32 typeId); void PrepareForNextVersion(); - void RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc = NULL); + void RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc = nullptr); bool IsPreparedForNextVersion() const {return m_RecordNextVersion; } void RegisterEventListener(IXmlHistoryEventListener* pEventListener); @@ -112,11 +112,11 @@ public: // Xml History Groups SXmlHistoryGroup* CreateXmlGroup(uint32 typeId); - void SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName = NULL, const TGroupIndexMap& groupIndex = TGroupIndexMap(), bool setExternal = false); + void SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName = nullptr, const TGroupIndexMap& groupIndex = TGroupIndexMap(), bool setExternal = false); const SXmlHistoryGroup* GetActiveGroup() const; const SXmlHistoryGroup* GetActiveGroup(TGroupIndexMap& currUserIndex /*out*/) const; - void AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = NULL); - void RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = NULL); + void AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = nullptr); + void RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = nullptr); void DeleteAll(); @@ -156,7 +156,7 @@ private: { SHistoryInfo() : IsNullUndo(false) - , CurrGroup(NULL) + , CurrGroup(nullptr) , HistoryInvalidated(false) {} const SXmlHistoryGroup* CurrGroup; @@ -174,7 +174,7 @@ private: struct SUndoEventHandlerData { SUndoEventHandlerData() - : CurrentData(NULL) {} + : CurrentData(nullptr) {} SXmlHistory* CurrentData; THistoryVersionMap HistoryData; @@ -203,9 +203,9 @@ private: void RecordNullUndo(const TEventHandlerList& eventHandler, const char* desc, bool isNull = true); void ReloadCurrentVersion(const SXmlHistoryGroup* pPrevGroup, int prevVersion); SXmlHistory* GetLatestHistory(SUndoEventHandlerData& eventHandlerData); - void NotifyUndoEventListener(IXmlHistoryEventListener::EHistoryEventType event, void* pData = NULL); + void NotifyUndoEventListener(IXmlHistoryEventListener::EHistoryEventType event, void* pData = nullptr); - void SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName = NULL, bool bRecordNullUndo = false, const TGroupIndexMap& groupIndex = TGroupIndexMap()); + void SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName = nullptr, bool bRecordNullUndo = false, const TGroupIndexMap& groupIndex = TGroupIndexMap()); void UnloadInt(); void ClearRedo(); diff --git a/Code/Editor/Util/XmlTemplate.cpp b/Code/Editor/Util/XmlTemplate.cpp index 1b0cc6ff6f..8acdd4973f 100644 --- a/Code/Editor/Util/XmlTemplate.cpp +++ b/Code/Editor/Util/XmlTemplate.cpp @@ -89,7 +89,7 @@ void CXmlTemplate::SetValues(const XmlNodeRef& node, XmlNodeRef& toNode) } else { - assert(!"NULL returned from node->GetChild()"); + assert(!"nullptr returned from node->GetChild()"); } } } @@ -125,7 +125,7 @@ bool CXmlTemplate::SetValues(const XmlNodeRef& node, XmlNodeRef& toNode, const X } else { - assert(!"NULL returned from node->GetChild()"); + assert(!"nullptr returned from node->GetChild()"); } } return false; @@ -193,7 +193,7 @@ void CXmlTemplateRegistry::LoadTemplates(const QString& path) XmlNodeRef child; // Construct the full filepath of the current file XmlNodeRef node = XmlHelpers::LoadXmlFromFile((dir + files[k].filename).toUtf8().data()); - if (node != 0 && node->isTag("Templates")) + if (node != nullptr && node->isTag("Templates")) { QString name; for (int i = 0; i < node->getChildCount(); i++) @@ -220,5 +220,5 @@ XmlNodeRef CXmlTemplateRegistry::FindTemplate(const QString& name) { return node; } - return 0; + return nullptr; } diff --git a/Code/Editor/Util/bitarray.h b/Code/Editor/Util/bitarray.h index c7d7f2012a..f55d195fd1 100644 --- a/Code/Editor/Util/bitarray.h +++ b/Code/Editor/Util/bitarray.h @@ -74,7 +74,7 @@ public: void flip() {* p ^= mask; } }; - CBitArray() { m_base = NULL; m_bits = NULL; m_size = 0; m_numBits = 0; }; + CBitArray() { m_base = nullptr; m_bits = nullptr; m_size = 0; m_numBits = 0; }; CBitArray(int numBits) { resize(numBits); }; ~CBitArray() { From 769fd7818911a80b654984072386acb366a031fb Mon Sep 17 00:00:00 2001 From: Nemerle Date: Thu, 5 Aug 2021 16:52:43 +0200 Subject: [PATCH 04/18] Editor code: tidy up BOOLs,NULLs and overrides pt6. A few 'typedefs' replaced by 'using's This shouldn't have any functional changes at all, just c++17 modernization It's a part 6 of a split #2847 Signed-off-by: Nemerle --- Code/Editor/LayoutWnd.h | 2 +- Code/Editor/LevelInfo.cpp | 2 +- Code/Editor/LogFile.cpp | 2 +- Code/Editor/MainWindow.cpp | 38 +++++++------- Code/Editor/NewLevelDialog.cpp | 8 +-- Code/Editor/NewTerrainDialog.cpp | 2 +- Code/Editor/Plugin.cpp | 4 +- Code/Editor/PluginManager.cpp | 18 +++---- Code/Editor/PythonEditorFuncs.cpp | 2 +- Code/Editor/ResizeResolutionDialog.cpp | 2 +- Code/Editor/ResourceSelectorHost.cpp | 2 +- Code/Editor/SelectEAXPresetDlg.cpp | 2 +- Code/Editor/Settings.cpp | 8 +-- Code/Editor/SettingsManager.cpp | 72 +++++++++++++------------- Code/Editor/SettingsManagerDialog.cpp | 2 +- Code/Editor/StartupLogoDialog.cpp | 8 +-- Code/Editor/StringDlg.h | 2 +- Code/Editor/ToolBox.cpp | 14 ++--- Code/Editor/ToolBox.h | 2 +- Code/Editor/ToolsConfigPage.cpp | 6 +-- Code/Editor/UIEnumsDatabase.cpp | 4 +- Code/Editor/UndoDropDown.cpp | 4 +- Code/Editor/ViewManager.cpp | 12 ++--- Code/Editor/ViewManager.h | 2 +- Code/Editor/ViewPane.cpp | 8 +-- Code/Editor/Viewport.cpp | 4 +- Code/Editor/Viewport.h | 10 ++-- Code/Editor/ViewportTitleDlg.cpp | 2 +- Code/Editor/WipFeatureManager.cpp | 20 +++---- Code/Editor/WipFeatureManager.h | 4 +- Code/Editor/WipFeaturesDlg.cpp | 2 +- Code/Editor/WipFeaturesDlg.h | 2 +- 32 files changed, 136 insertions(+), 136 deletions(-) diff --git a/Code/Editor/LayoutWnd.h b/Code/Editor/LayoutWnd.h index 106c32d0a0..918734ebb9 100644 --- a/Code/Editor/LayoutWnd.h +++ b/Code/Editor/LayoutWnd.h @@ -103,7 +103,7 @@ public: static const char* GetConfigGroupName(); CLayoutViewPane* FindViewByClass(const QString& viewClassName); - void BindViewport(CLayoutViewPane* vp, const QString& viewClassName, QWidget* pViewport = NULL); + void BindViewport(CLayoutViewPane* vp, const QString& viewClassName, QWidget* pViewport = nullptr); QString ViewportTypeToClassName(EViewportType viewType); //! Switch 2D viewports. diff --git a/Code/Editor/LevelInfo.cpp b/Code/Editor/LevelInfo.cpp index 5821f9c933..5ad7a6593d 100644 --- a/Code/Editor/LevelInfo.cpp +++ b/Code/Editor/LevelInfo.cpp @@ -93,7 +93,7 @@ void CLevelInfo::ValidateObjects() pObject->Validate(m_pReport); - m_pReport->SetCurrentValidatorObject(NULL); + m_pReport->SetCurrentValidatorObject(nullptr); } CLogFile::WriteLine("Validating Duplicate Objects..."); diff --git a/Code/Editor/LogFile.cpp b/Code/Editor/LogFile.cpp index 8c04eab58c..c768f5013b 100644 --- a/Code/Editor/LogFile.cpp +++ b/Code/Editor/LogFile.cpp @@ -380,7 +380,7 @@ AZ_POP_DISABLE_WARNING ////////////////////////////////////////////////////////////////////// #if defined(AZ_PLATFORM_WINDOWS) - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig); + EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &DisplayConfig); GetPrivateProfileString("boot.description", "display.drv", "(Unknown graphics card)", szProfileBuffer, sizeof(szProfileBuffer), "system.ini"); diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index ff322b79ac..3fba3fea6b 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -160,45 +160,45 @@ public: } } - ~EngineConnectionListener() + ~EngineConnectionListener() override { AzFramework::AssetSystemInfoBus::Handler::BusDisconnect(); AzFramework::EngineConnectionEvents::Bus::Handler::BusDisconnect(); } public: - virtual void Connected([[maybe_unused]] AzFramework::SocketConnection* connection) + void Connected([[maybe_unused]] AzFramework::SocketConnection* connection) override { m_state = EConnectionState::Connected; } - virtual void Connecting([[maybe_unused]] AzFramework::SocketConnection* connection) + void Connecting([[maybe_unused]] AzFramework::SocketConnection* connection) override { m_state = EConnectionState::Connecting; } - virtual void Listening([[maybe_unused]] AzFramework::SocketConnection* connection) + void Listening([[maybe_unused]] AzFramework::SocketConnection* connection) override { m_state = EConnectionState::Listening; } - virtual void Disconnecting([[maybe_unused]] AzFramework::SocketConnection* connection) + void Disconnecting([[maybe_unused]] AzFramework::SocketConnection* connection) override { m_state = EConnectionState::Disconnecting; } - virtual void Disconnected([[maybe_unused]] AzFramework::SocketConnection* connection) + void Disconnected([[maybe_unused]] AzFramework::SocketConnection* connection) override { m_state = EConnectionState::Disconnected; } - virtual void AssetCompilationSuccess(const AZStd::string& assetPath) override + void AssetCompilationSuccess(const AZStd::string& assetPath) override { m_lastAssetProcessorTask = assetPath; } - virtual void AssetCompilationFailed(const AZStd::string& assetPath) override + void AssetCompilationFailed(const AZStd::string& assetPath) override { m_failedJobs.insert(assetPath); } - virtual void CountOfAssetsInQueue(const int& count) override + void CountOfAssetsInQueue(const int& count) override { m_pendingJobsCount = count; } @@ -298,7 +298,7 @@ MainWindow::MainWindow(QWidget* parent) , m_undoStateAdapter(new UndoStackStateAdapter(this)) , m_keyboardCustomization(nullptr) , m_activeView(nullptr) - , m_settings("O3DE", "O3DE") + , m_settings("O3DE", "O3DE") , m_toolbarManager(new ToolbarManager(m_actionManager, this)) , m_assetImporterManager(new AssetImporterManager(this)) , m_levelEditorMenuHandler(new LevelEditorMenuHandler(this, m_viewPaneManager, m_settings)) @@ -573,7 +573,7 @@ void MainWindow::closeEvent(QCloseEvent* event) if (GetIEditor()->GetDocument()) { - GetIEditor()->GetDocument()->SetModifiedFlag(FALSE); + GetIEditor()->GetDocument()->SetModifiedFlag(false); GetIEditor()->GetDocument()->SetModifiedModules(eModifiedNothing); } // Close all edit panels. @@ -581,7 +581,7 @@ void MainWindow::closeEvent(QCloseEvent* event) GetIEditor()->GetObjectManager()->EndEditParams(); // force clean up of all deferred deletes, so that we don't have any issues with windows from plugins not being deleted yet - qApp->sendPostedEvents(0, QEvent::DeferredDelete); + qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete); QMainWindow::closeEvent(event); } @@ -1243,7 +1243,7 @@ void MainWindow::OnEditorNotifyEvent(EEditorNotifyEvent ev) auto cryEdit = CCryEditApp::instance(); if (cryEdit) { - cryEdit->SetEditorWindowTitle(0, AZ::Utils::GetProjectName().c_str(), GetIEditor()->GetGameEngine()->GetLevelName()); + cryEdit->SetEditorWindowTitle(nullptr, AZ::Utils::GetProjectName().c_str(), GetIEditor()->GetGameEngine()->GetLevelName()); } } break; @@ -1252,7 +1252,7 @@ void MainWindow::OnEditorNotifyEvent(EEditorNotifyEvent ev) auto cryEdit = CCryEditApp::instance(); if (cryEdit) { - cryEdit->SetEditorWindowTitle(0, AZ::Utils::GetProjectName().c_str(), 0); + cryEdit->SetEditorWindowTitle(nullptr, AZ::Utils::GetProjectName().c_str(), nullptr); } } break; @@ -1351,8 +1351,8 @@ void MainWindow::ResetAutoSaveTimers(bool bForceInit) { delete m_autoRemindTimer; } - m_autoSaveTimer = 0; - m_autoRemindTimer = 0; + m_autoSaveTimer = nullptr; + m_autoRemindTimer = nullptr; if (bForceInit) { @@ -1389,7 +1389,7 @@ void MainWindow::ResetBackgroundUpdateTimer() if (m_backgroundUpdateTimer) { delete m_backgroundUpdateTimer; - m_backgroundUpdateTimer = 0; + m_backgroundUpdateTimer = nullptr; } ICVar* pBackgroundUpdatePeriod = gEnv->pConsole->GetCVar("ed_backgroundUpdatePeriod"); @@ -1435,7 +1435,7 @@ void MainWindow::OnRefreshAudioSystem() if (QString::compare(sLevelName, "Untitled", Qt::CaseInsensitive) == 0) { - // Rather pass NULL to indicate that no level is loaded! + // Rather pass nullptr to indicate that no level is loaded! sLevelName = QString(); } @@ -1868,7 +1868,7 @@ QWidget* MainWindow::CreateToolbarWidget(int actionId) break; case ID_TOOLBAR_WIDGET_SPACER_RIGHT: w = CreateSpacerRightWidget(); - break; + break; default: qWarning() << Q_FUNC_INFO << "Unknown id " << actionId; return nullptr; diff --git a/Code/Editor/NewLevelDialog.cpp b/Code/Editor/NewLevelDialog.cpp index 7db795333b..29445cef2b 100644 --- a/Code/Editor/NewLevelDialog.cpp +++ b/Code/Editor/NewLevelDialog.cpp @@ -19,7 +19,7 @@ #include // Editor -#include "NewTerrainDialog.h" +#include "NewTerrainDialog.h" AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include @@ -54,7 +54,7 @@ private: // CNewLevelDialog dialog -CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) +CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , m_bUpdate(false) , ui(new Ui::CNewLevelDialog) @@ -69,7 +69,7 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) m_bIsResize = false; - + ui->TITLE->setText(tr("Assign a name and location to the new level.")); ui->STATIC1->setText(tr("Location:")); ui->STATIC2->setText(tr("Name:")); @@ -98,7 +98,7 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) m_levelFolders = GetLevelsFolder(); m_level = ""; - // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which + // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which // widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last. // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus(). diff --git a/Code/Editor/NewTerrainDialog.cpp b/Code/Editor/NewTerrainDialog.cpp index 16641ee275..0e66482eb4 100644 --- a/Code/Editor/NewTerrainDialog.cpp +++ b/Code/Editor/NewTerrainDialog.cpp @@ -19,7 +19,7 @@ AZ_POP_DISABLE_WARNING -CNewTerrainDialog::CNewTerrainDialog(QWidget* pParent /*=NULL*/) +CNewTerrainDialog::CNewTerrainDialog(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , m_terrainResolutionIndex(0) , m_terrainUnitsIndex(0) diff --git a/Code/Editor/Plugin.cpp b/Code/Editor/Plugin.cpp index 0fb37c96c7..e73b9daa2c 100644 --- a/Code/Editor/Plugin.cpp +++ b/Code/Editor/Plugin.cpp @@ -133,7 +133,7 @@ IClassDesc* CClassFactory::FindClass(const char* pClassName) const if (!pSubClassName) { - return NULL; + return nullptr; } QString name = QString(pClassName).left(pSubClassName - pClassName); @@ -169,7 +169,7 @@ void CClassFactory::UnregisterClass(const char* pClassName) { IClassDesc* pClassDesc = FindClass(pClassName); - if (pClassDesc == NULL) + if (pClassDesc == nullptr) { return; } diff --git a/Code/Editor/PluginManager.cpp b/Code/Editor/PluginManager.cpp index f03cb54fce..5efd52a97e 100644 --- a/Code/Editor/PluginManager.cpp +++ b/Code/Editor/PluginManager.cpp @@ -18,8 +18,8 @@ #include "Include/IPlugin.h" -typedef IPlugin* (* TPfnCreatePluginInstance)(PLUGIN_INIT_PARAM* pInitParam); -typedef void (* TPfnQueryPluginSettings)(SPluginSettings&); +using TPfnCreatePluginInstance = IPlugin *(*)(PLUGIN_INIT_PARAM *pInitParam); +using TPfnQueryPluginSettings = void (*)(SPluginSettings &); CPluginManager::CPluginManager() { @@ -210,7 +210,7 @@ bool CPluginManager::LoadPlugins(const char* pPathWithMask) continue; } - IPlugin* pPlugin = NULL; + IPlugin* pPlugin = nullptr; PLUGIN_INIT_PARAM sInitParam = { GetIEditor(), @@ -279,7 +279,7 @@ IPlugin* CPluginManager::GetPluginByGUID(const char* pGUID) } } - return NULL; + return nullptr; } IPlugin* CPluginManager::GetPluginByUIID(uint8 iUserInterfaceID) @@ -290,7 +290,7 @@ IPlugin* CPluginManager::GetPluginByUIID(uint8 iUserInterfaceID) if (it == m_uuidPluginMap.end()) { - return NULL; + return nullptr; } return (*it).second; @@ -302,7 +302,7 @@ IUIEvent* CPluginManager::GetEventByIDAndPluginID(uint8 aPluginID, uint8 aEventI // specified by its ID and the user interface ID of the plugin which // created the UI element - IPlugin* pPlugin = NULL; + IPlugin* pPlugin = nullptr; TEventHandlerIt eventIt; TPluginEventIt pluginIt; @@ -310,21 +310,21 @@ IUIEvent* CPluginManager::GetEventByIDAndPluginID(uint8 aPluginID, uint8 aEventI if (!pPlugin) { - return NULL; + return nullptr; } pluginIt = m_pluginEventMap.find(pPlugin); if (pluginIt == m_pluginEventMap.end()) { - return NULL; + return nullptr; } eventIt = (*pluginIt).second.find(aEventID); if (eventIt == (*pluginIt).second.end()) { - return NULL; + return nullptr; } return (*eventIt).second; diff --git a/Code/Editor/PythonEditorFuncs.cpp b/Code/Editor/PythonEditorFuncs.cpp index 93f5f8f10f..2b7bca3b0b 100644 --- a/Code/Editor/PythonEditorFuncs.cpp +++ b/Code/Editor/PythonEditorFuncs.cpp @@ -323,7 +323,7 @@ namespace ////////////////////////////////////////////////////////////////////////// void GetPythonArgumentsVector(const char* pArguments, QStringList& inputArguments) { - if (pArguments == NULL) + if (pArguments == nullptr) { return; } diff --git a/Code/Editor/ResizeResolutionDialog.cpp b/Code/Editor/ResizeResolutionDialog.cpp index ad57650afa..f2a03fb1b2 100644 --- a/Code/Editor/ResizeResolutionDialog.cpp +++ b/Code/Editor/ResizeResolutionDialog.cpp @@ -89,7 +89,7 @@ int ResizeResolutionModel::SizeRow(uint32 dwSize) const // CResizeResolutionDialog dialog -CResizeResolutionDialog::CResizeResolutionDialog(QWidget* pParent /*=NULL*/) +CResizeResolutionDialog::CResizeResolutionDialog(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , m_model(new ResizeResolutionModel(this)) , ui(new Ui::CResizeResolutionDialog) diff --git a/Code/Editor/ResourceSelectorHost.cpp b/Code/Editor/ResourceSelectorHost.cpp index d265b3ffbe..af6c398fe7 100644 --- a/Code/Editor/ResourceSelectorHost.cpp +++ b/Code/Editor/ResourceSelectorHost.cpp @@ -101,7 +101,7 @@ public: } private: - typedef std::map > TTypeMap; + using TTypeMap = std::map>; TTypeMap m_typeMap; std::map m_globallySelectedResources; diff --git a/Code/Editor/SelectEAXPresetDlg.cpp b/Code/Editor/SelectEAXPresetDlg.cpp index 4a5ea9b66c..733de8b9cf 100644 --- a/Code/Editor/SelectEAXPresetDlg.cpp +++ b/Code/Editor/SelectEAXPresetDlg.cpp @@ -49,7 +49,7 @@ QString CSelectEAXPresetDlg::GetCurrPreset() const { return m_ui->listView->currentIndex().data().toString(); } - // EXCEPTION: OCX Property Pages should return FALSE + // EXCEPTION: OCX Property Pages should return false return QString(); } diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 8f86c74b25..40d53a340c 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -243,7 +243,7 @@ SEditorSettings::SEditorSettings() gui.nToolbarIconSize = static_cast(AzQtComponents::ToolBar::ToolBarIconSize::Default); - int lfHeight = 8;// -MulDiv(8, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72); + int lfHeight = 8;// -MulDiv(8, GetDeviceCaps(GetDC(nullptr), LOGPIXELSY), 72); gui.nDefaultFontHieght = lfHeight; gui.hSystemFont = QFont("Ms Shell Dlg 2", lfHeight, QFont::Normal); gui.hSystemFontBold = QFont("Ms Shell Dlg 2", lfHeight, QFont::Bold); @@ -530,7 +530,7 @@ void SEditorSettings::Save() SaveValue("Settings", "ShowTimeInConsole", bShowTimeInConsole); SaveValue("Settings", "EnableSceneInspector", enableSceneInspector); - + ////////////////////////////////////////////////////////////////////////// // Viewport settings. ////////////////////////////////////////////////////////////////////////// @@ -623,7 +623,7 @@ void SEditorSettings::Save() SaveValue("Settings\\AssetBrowser", "AutoFilterFromViewportSelection", sAssetBrowserSettings.bAutoFilterFromViewportSelection); SaveValue("Settings\\AssetBrowser", "VisibleColumnNames", sAssetBrowserSettings.sVisibleColumnNames); SaveValue("Settings\\AssetBrowser", "ColumnNames", sAssetBrowserSettings.sColumnNames); - + ////////////////////////////////////////////////////////////////////////// // Deep Selection Settings ////////////////////////////////////////////////////////////////////////// @@ -702,7 +702,7 @@ void SEditorSettings::Load() QString strPlaceholderString; // Load settings from registry. LoadValue("Settings", "UndoLevels", undoLevels); - LoadValue("Settings", "UndoSliceOverrideSaveValue", m_undoSliceOverrideSaveValue); + LoadValue("Settings", "UndoSliceOverrideSaveValue", m_undoSliceOverrideSaveValue); LoadValue("Settings", "ShowWelcomeScreenAtStartup", bShowDashboardAtStartup); LoadValue("Settings", "ShowCircularDependencyError", m_showCircularDependencyError); LoadValue("Settings", "LoadLastLevelAtStartup", bAutoloadLastLevelAtStartup); diff --git a/Code/Editor/SettingsManager.cpp b/Code/Editor/SettingsManager.cpp index 82e3eaf1e6..27031ca43e 100644 --- a/Code/Editor/SettingsManager.cpp +++ b/Code/Editor/SettingsManager.cpp @@ -105,7 +105,7 @@ bool CSettingsManager::CreateDefaultLayoutSettingsFile() AZStd::vector CSettingsManager::BuildSettingsList() { - XmlNodeRef root = NULL; + XmlNodeRef root = nullptr; root = m_pSettingsManagerMemoryNode; @@ -132,8 +132,8 @@ void CSettingsManager::BuildSettingsList_Helper(const XmlNodeRef& node, const AZ { for (int i = 0; i < node->getNumAttributes(); ++i) { - const char* key = NULL; - const char* value = NULL; + const char* key = nullptr; + const char* value = nullptr; node->getAttributeByIndex(i, &key, &value); if (!pathToNode.empty()) { @@ -163,7 +163,7 @@ void CSettingsManager::BuildSettingsList_Helper(const XmlNodeRef& node, const AZ result ); } - + } } } @@ -190,7 +190,7 @@ void CSettingsManager::SaveSetting(const QString& path, const QString& attr, con // Spaces in node names not allowed writeAttr.replace(" ", ""); - XmlNodeRef root = NULL; + XmlNodeRef root = nullptr; root = m_pSettingsManagerMemoryNode; @@ -276,11 +276,11 @@ XmlNodeRef CSettingsManager::LoadSetting(const QString& path, const QString& att // Spaces in node names not allowed readAttr.replace(" ", ""); - XmlNodeRef root = NULL; + XmlNodeRef root = nullptr; root = m_pSettingsManagerMemoryNode; - XmlNodeRef tmpNode = NULL; + XmlNodeRef tmpNode = nullptr; if (NeedSettingsNode(path)) { @@ -293,7 +293,7 @@ XmlNodeRef CSettingsManager::LoadSetting(const QString& path, const QString& att if (!tmpNode) { - return 0; + return nullptr; } for (int i = 0; i < strNodes.size(); ++i) @@ -304,13 +304,13 @@ XmlNodeRef CSettingsManager::LoadSetting(const QString& path, const QString& att } else { - return 0; + return nullptr; } } if (!tmpNode->findChild(readAttr.toUtf8().data())) { - return 0; + return nullptr; } else { @@ -360,7 +360,7 @@ void CSettingsManager::AddToolVersion(const QString& toolName, const QString& to return; } - if (stl::find_in_map(m_toolNames, toolName, NULL) == "") + if (stl::find_in_map(m_toolNames, toolName, nullptr) == "") { if (!toolVersion.isEmpty()) { @@ -380,7 +380,7 @@ void CSettingsManager::AddToolName(const QString& toolName, const QString& human return; } - if (stl::find_in_map(m_toolNames, toolName, NULL) == "") + if (stl::find_in_map(m_toolNames, toolName, nullptr) == "") { if (!humanReadableName.isEmpty()) { @@ -499,7 +499,7 @@ void CSettingsManager::GetMatchingLayoutNames(TToolNamesMap& foundTools, XmlNode return; } - TToolNamesMap* toolNames = NULL; + TToolNamesMap* toolNames = nullptr; if (!foundTools.empty()) { @@ -593,11 +593,11 @@ bool CSettingsManager::NeedSettingsNode(const QString& path) { if ((path != EDITOR_LAYOUT_ROOT_NODE) && (path != TOOLBOX_NODE) && (path != TOOLBOXMACROS_NODE)) { - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -605,13 +605,13 @@ void CSettingsManager::SerializeCVars(XmlNodeRef& node, bool bLoad) { int nNumberOfVariables(0); int nCurrentVariable(0); - IConsole* piConsole(NULL); - ICVar* piVariable(NULL); + IConsole* piConsole(nullptr); + ICVar* piVariable(nullptr); std::vector cszVariableNames; - char* szKey(NULL); - char* szValue(NULL); - ICVar* piCVar(NULL); + char* szKey(nullptr); + char* szValue(nullptr); + ICVar* piCVar(nullptr); piConsole = gEnv->pConsole; @@ -622,7 +622,7 @@ void CSettingsManager::SerializeCVars(XmlNodeRef& node, bool bLoad) if (bLoad) { - XmlNodeRef readNode = NULL; + XmlNodeRef readNode = nullptr; XmlNodeRef inputCVarsNode = node->findChild(CVARS_NODE); if (!inputCVarsNode) @@ -649,7 +649,7 @@ void CSettingsManager::SerializeCVars(XmlNodeRef& node, bool bLoad) } else { - XmlNodeRef newCVarNode = NULL; + XmlNodeRef newCVarNode = nullptr; XmlNodeRef oldCVarsNode = node->findChild(CVARS_NODE); if (oldCVarsNode) @@ -660,9 +660,9 @@ void CSettingsManager::SerializeCVars(XmlNodeRef& node, bool bLoad) XmlNodeRef cvarsNode = XmlHelpers::CreateXmlNode(CVARS_NODE); nNumberOfVariables = piConsole->GetNumVisibleVars(); - cszVariableNames.resize(nNumberOfVariables, NULL); + cszVariableNames.resize(nNumberOfVariables, nullptr); - if (piConsole->GetSortedVars((const char**)&cszVariableNames.front(), nNumberOfVariables, NULL) != nNumberOfVariables) + if (piConsole->GetSortedVars((const char**)&cszVariableNames.front(), nNumberOfVariables, nullptr) != nNumberOfVariables) { assert(false); return; @@ -711,8 +711,8 @@ void CSettingsManager::ReadValueStr(XmlNodeRef& sourceNode, const QString& path, // Spaces in node names not allowed readAttr.replace(" ", ""); - XmlNodeRef root = NULL; - XmlNodeRef tmpNode = NULL; + XmlNodeRef root = nullptr; + XmlNodeRef tmpNode = nullptr; if (NeedSettingsNode(path)) { @@ -809,7 +809,7 @@ bool CSettingsManager::IsEventSafe(const SEventLog& event) if (!root) { - return TRUE; + return true; } QString eventName = event.m_eventName; @@ -823,7 +823,7 @@ bool CSettingsManager::IsEventSafe(const SEventLog& event) // Log entry not found, so it is safe to start if (!resNode) { - return TRUE; + return true; } XmlNodeRef callerVersion = resNode->findChild(EVENT_LOG_CALLER_VERSION); @@ -841,15 +841,15 @@ bool CSettingsManager::IsEventSafe(const SEventLog& event) { if (callerVersionStr != GetToolVersion(eventName)) { - return TRUE; + return true; } } // The same version of tool/level found - return FALSE; + return false; } - return TRUE; + return true; } ////////////////////////////////////////////////////////////////////////// @@ -947,15 +947,15 @@ XmlNodeRef CSettingsManager::LoadLogEventSetting(const QString& path, const QStr if (!root) { - return 0; + return nullptr; } - XmlNodeRef tmpNode = NULL; + XmlNodeRef tmpNode = nullptr; tmpNode = root; if (!tmpNode) { - return 0; + return nullptr; } for (int i = 0; i < strNodes.size(); ++i) @@ -966,7 +966,7 @@ XmlNodeRef CSettingsManager::LoadLogEventSetting(const QString& path, const QStr } else { - return 0; + return nullptr; } } @@ -975,7 +975,7 @@ XmlNodeRef CSettingsManager::LoadLogEventSetting(const QString& path, const QStr return tmpNode; } - return 0; + return nullptr; } QString CSettingsManager::GenerateContentHash(XmlNodeRef& node, QString sourceName) diff --git a/Code/Editor/SettingsManagerDialog.cpp b/Code/Editor/SettingsManagerDialog.cpp index 3f1c718b38..f8b720ae55 100644 --- a/Code/Editor/SettingsManagerDialog.cpp +++ b/Code/Editor/SettingsManagerDialog.cpp @@ -84,7 +84,7 @@ void CSettingsManagerDialog::OnReadBtnClick() ui->m_layoutListBox->clear(); TToolNamesMap toolNames; - XmlNodeRef dummyNode = NULL; + XmlNodeRef dummyNode = nullptr; GetIEditor()->GetSettingsManager()->GetMatchingLayoutNames(toolNames, dummyNode, m_importFileStr); diff --git a/Code/Editor/StartupLogoDialog.cpp b/Code/Editor/StartupLogoDialog.cpp index 38d733f8df..d9625aff1a 100644 --- a/Code/Editor/StartupLogoDialog.cpp +++ b/Code/Editor/StartupLogoDialog.cpp @@ -27,14 +27,14 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING ///////////////////////////////////////////////////////////////////////////// // CStartupLogoDialog dialog -CStartupLogoDialog* CStartupLogoDialog::s_pLogoWindow = 0; +CStartupLogoDialog* CStartupLogoDialog::s_pLogoWindow = nullptr; -CStartupLogoDialog::CStartupLogoDialog(QString versionText, QString richTextCopyrightNotice, QWidget* pParent /*=NULL*/) +CStartupLogoDialog::CStartupLogoDialog(QString versionText, QString richTextCopyrightNotice, QWidget* pParent /*=nullptr*/) : QWidget(pParent, Qt::Dialog | Qt::FramelessWindowHint) , m_ui(new Ui::StartupLogoDialog) { m_ui->setupUi(this); - + s_pLogoWindow = this; m_backgroundImage = QPixmap(QStringLiteral(":/StartupLogoDialog/splashscreen_background_developer_preview.jpg")); @@ -61,7 +61,7 @@ CStartupLogoDialog::CStartupLogoDialog(QString versionText, QString richTextCopy CStartupLogoDialog::~CStartupLogoDialog() { - s_pLogoWindow = 0; + s_pLogoWindow = nullptr; } void CStartupLogoDialog::SetText(const char* text) diff --git a/Code/Editor/StringDlg.h b/Code/Editor/StringDlg.h index a1ee3908c7..e52cd207d1 100644 --- a/Code/Editor/StringDlg.h +++ b/Code/Editor/StringDlg.h @@ -25,7 +25,7 @@ typedef bool (StringDlgPredicate)(QString input); class StringDlg : public QInputDialog { public: - StringDlg(const QString &title, QWidget* pParent = NULL, bool bFileNameLimitation = false); + StringDlg(const QString &title, QWidget* pParent = nullptr, bool bFileNameLimitation = false); void SetCheckCallback(const std::function& Check) { m_Check = Check; diff --git a/Code/Editor/ToolBox.cpp b/Code/Editor/ToolBox.cpp index 82817e1ff7..bac02d7460 100644 --- a/Code/Editor/ToolBox.cpp +++ b/Code/Editor/ToolBox.cpp @@ -186,7 +186,7 @@ const CToolBoxMacro* CToolBoxManager::GetMacro(int iIndex, bool bToolbox) const assert(0 <= iIndex && iIndex < m_shelveMacros.size()); return m_shelveMacros[iIndex]; } - return NULL; + return nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -202,7 +202,7 @@ CToolBoxMacro* CToolBoxManager::GetMacro(int iIndex, bool bToolbox) assert(0 <= iIndex && iIndex < m_shelveMacros.size()); return m_shelveMacros[iIndex]; } - return NULL; + return nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -240,14 +240,14 @@ CToolBoxMacro* CToolBoxManager::NewMacro(const QString& title, bool bToolbox, in const int macroCount = m_macros.size(); if (macroCount > ID_TOOL_LAST - ID_TOOL_FIRST + 1) { - return NULL; + return nullptr; } for (size_t i = 0; i < macroCount; ++i) { if (QString::compare(m_macros[i]->GetTitle(), title, Qt::CaseInsensitive) == 0) { - return NULL; + return nullptr; } } @@ -264,7 +264,7 @@ CToolBoxMacro* CToolBoxManager::NewMacro(const QString& title, bool bToolbox, in const int shelveMacroCount = m_shelveMacros.size(); if (shelveMacroCount > ID_TOOL_SHELVE_LAST - ID_TOOL_SHELVE_FIRST + 1) { - return NULL; + return nullptr; } CToolBoxMacro* pNewTool = new CToolBoxMacro(title); @@ -275,7 +275,7 @@ CToolBoxMacro* CToolBoxManager::NewMacro(const QString& title, bool bToolbox, in m_shelveMacros.push_back(pNewTool); return pNewTool; } - return NULL; + return nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -333,7 +333,7 @@ void CToolBoxManager::Load([[maybe_unused]] ActionManager* actionManager) void CToolBoxManager::Load(QString xmlpath, AmazonToolbar* pToolbar, bool bToolbox, ActionManager* actionManager) { XmlNodeRef toolBoxNode = XmlHelpers::LoadXmlFromFile(xmlpath.toUtf8().data()); - if (toolBoxNode == NULL) + if (toolBoxNode == nullptr) { return; } diff --git a/Code/Editor/ToolBox.h b/Code/Editor/ToolBox.h index 0c91305c79..eefc74f791 100644 --- a/Code/Editor/ToolBox.h +++ b/Code/Editor/ToolBox.h @@ -137,7 +137,7 @@ public: CToolBoxMacro* GetMacro(int iIndex, bool bToolbox); //! Get the index of a macro from its title. int GetMacroIndex(const QString& title, bool bToolbox) const; - //! Creates a new macro in the manager. If the title is duplicate, this returns NULL. + //! Creates a new macro in the manager. If the title is duplicate, this returns nullptr. CToolBoxMacro* NewMacro(const QString& title, bool bToolbox, int* newIdx); //! Try to change the title of a macro. If the title is duplicate, the change is aborted and this returns false. bool SetMacroTitle(int index, const QString& title, bool bToolbox); diff --git a/Code/Editor/ToolsConfigPage.cpp b/Code/Editor/ToolsConfigPage.cpp index a2328550e0..bae70f0cfe 100644 --- a/Code/Editor/ToolsConfigPage.cpp +++ b/Code/Editor/ToolsConfigPage.cpp @@ -109,7 +109,7 @@ private: QStringList m_iconFiles; }; -CIconListDialog::CIconListDialog(QWidget* pParent /* = NULL */) +CIconListDialog::CIconListDialog(QWidget* pParent /* = nullptr */) : QDialog(pParent) , m_ui(new Ui::IconListDialog) { @@ -498,7 +498,7 @@ CToolsConfigPage::CToolsConfigPage(QWidget* parent) QKeySequence shortcut(value); m_ui->m_macroShortcutKey->setKeySequence(shortcut); } - + if (m_ui->m_macroShortcutKey->keySequence().count() >= 1) { m_ui->m_assignShortcut->setEnabled(true); @@ -703,7 +703,7 @@ void CToolsConfigPage::OnAssignMacroShortcut() { auto pShortcutMgr = MainWindow::instance()->GetShortcutManager(); - if (pShortcutMgr == NULL) + if (pShortcutMgr == nullptr) { return; } diff --git a/Code/Editor/UIEnumsDatabase.cpp b/Code/Editor/UIEnumsDatabase.cpp index f0496f64e3..b859f54ffa 100644 --- a/Code/Editor/UIEnumsDatabase.cpp +++ b/Code/Editor/UIEnumsDatabase.cpp @@ -59,7 +59,7 @@ void CUIEnumsDatabase::SetEnumStrings(const QString& enumName, const QStringList { int nStringCount = sStringsArray.size(); - CUIEnumsDatabase_SEnum* pEnum = stl::find_in_map(m_enums, enumName, 0); + CUIEnumsDatabase_SEnum* pEnum = stl::find_in_map(m_enums, enumName, nullptr); if (!pEnum) { pEnum = new CUIEnumsDatabase_SEnum; @@ -86,6 +86,6 @@ void CUIEnumsDatabase::SetEnumStrings(const QString& enumName, const QStringList ////////////////////////////////////////////////////////////////////////// CUIEnumsDatabase_SEnum* CUIEnumsDatabase::FindEnum(const QString& enumName) const { - CUIEnumsDatabase_SEnum* pEnum = stl::find_in_map(m_enums, enumName, 0); + CUIEnumsDatabase_SEnum* pEnum = stl::find_in_map(m_enums, enumName, nullptr); return pEnum; } diff --git a/Code/Editor/UndoDropDown.cpp b/Code/Editor/UndoDropDown.cpp index 669c05ecaa..fbe18d5d52 100644 --- a/Code/Editor/UndoDropDown.cpp +++ b/Code/Editor/UndoDropDown.cpp @@ -56,7 +56,7 @@ public: m_manager.AddListener(this); } - virtual ~UndoDropDownListModel() + ~UndoDropDownListModel() override { m_manager.RemoveListener(this); } @@ -81,7 +81,7 @@ public: return m_stackNames[index.row()]; } - void SignalNumUndoRedo(const unsigned int& numUndo, const unsigned int& numRedo) + void SignalNumUndoRedo(const unsigned int& numUndo, const unsigned int& numRedo) override { std::vector fresh; if (UndoRedoDirection::Undo == m_direction && m_stackNames.size() != numUndo) diff --git a/Code/Editor/ViewManager.cpp b/Code/Editor/ViewManager.cpp index 5a3e92a525..d5d932dae1 100644 --- a/Code/Editor/ViewManager.cpp +++ b/Code/Editor/ViewManager.cpp @@ -55,7 +55,7 @@ CViewManager::CViewManager() m_updateRegion.min = Vec3(-100000, -100000, -100000); m_updateRegion.max = Vec3(100000, 100000, 100000); - m_pSelectedView = NULL; + m_pSelectedView = nullptr; m_nGameViewports = 0; m_bGameViewportsUpdated = false; @@ -117,7 +117,7 @@ void CViewManager::UnregisterViewport(CViewport* pViewport) { if (m_pSelectedView == pViewport) { - m_pSelectedView = NULL; + m_pSelectedView = nullptr; } stl::find_and_erase(m_viewports, pViewport); m_bGameViewportsUpdated = false; @@ -137,7 +137,7 @@ CViewport* CViewManager::GetViewport(EViewportType type) const return m_viewports[i]; } } - return 0; + return nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -150,7 +150,7 @@ CViewport* CViewManager::GetViewport(const QString& name) const return m_viewports[i]; } } - return 0; + return nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -234,7 +234,7 @@ void CViewManager::SelectViewport(CViewport* pViewport) { // Audio: Handle viewport change for listeners - if (m_pSelectedView != NULL && m_pSelectedView != pViewport) + if (m_pSelectedView != nullptr && m_pSelectedView != pViewport) { m_pSelectedView->SetSelected(false); @@ -242,7 +242,7 @@ void CViewManager::SelectViewport(CViewport* pViewport) m_pSelectedView = pViewport; - if (m_pSelectedView != NULL) + if (m_pSelectedView != nullptr) { m_pSelectedView->SetSelected(true); } diff --git a/Code/Editor/ViewManager.h b/Code/Editor/ViewManager.h index 22f9f6804f..b62ece89ac 100644 --- a/Code/Editor/ViewManager.h +++ b/Code/Editor/ViewManager.h @@ -93,7 +93,7 @@ public: ////////////////////////////////////////////////////////////////////////// //! Get current layout window. - //! @return Pointer to the layout window, can be NULL. + //! @return Pointer to the layout window, can be nullptr. virtual CLayoutWnd* GetLayout() const; //! Cycle between different 2D viewports type on same view pane. diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index 19b653b865..1d530ece48 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -159,8 +159,8 @@ CLayoutViewPane::CLayoutViewPane(QWidget* parent) , m_viewportTitleDlg(this) , m_expanderWatcher(new ViewportTitleExpanderWatcher(this, &m_viewportTitleDlg)) { - m_viewport = 0; - m_active = 0; + m_viewport = nullptr; + m_active = false; m_nBorder = VIEW_BORDER; m_bFullscreen = false; @@ -338,7 +338,7 @@ void CLayoutViewPane::DetachViewport() { DisconnectRenderViewportInteractionRequestBus(); OnFOVChanged(gSettings.viewports.fDefaultFov); - m_viewport = 0; + m_viewport = nullptr; } ////////////////////////////////////////////////////////////////////////// @@ -348,7 +348,7 @@ void CLayoutViewPane::ReleaseViewport() { DisconnectRenderViewportInteractionRequestBus(); m_viewport->deleteLater(); - m_viewport = 0; + m_viewport = nullptr; } } diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp index 906a60ac47..2cc9c78e4b 100644 --- a/Code/Editor/Viewport.cpp +++ b/Code/Editor/Viewport.cpp @@ -192,7 +192,7 @@ QtViewport::QtViewport(QWidget* parent) m_viewTM.SetIdentity(); m_screenTM.SetIdentity(); - m_pMouseOverObject = 0; + m_pMouseOverObject = nullptr; m_bAdvancedSelectMode = false; @@ -398,7 +398,7 @@ void QtViewport::OnDeactivate() ////////////////////////////////////////////////////////////////////////// void QtViewport::ResetContent() { - m_pMouseOverObject = 0; + m_pMouseOverObject = nullptr; // Need to clear visual object cache. // Right after loading new level, some code(e.g. OnMouseMove) access invalid diff --git a/Code/Editor/Viewport.h b/Code/Editor/Viewport.h index c94a77b06e..0a23d93d0d 100644 --- a/Code/Editor/Viewport.h +++ b/Code/Editor/Viewport.h @@ -113,7 +113,7 @@ public: virtual void AddPostRenderer(IPostRenderer* pPostRenderer) = 0; virtual bool RemovePostRenderer(IPostRenderer* pPostRenderer) = 0; - virtual BOOL DestroyWindow() { return FALSE; } + virtual bool DestroyWindow() { return false; } /** Get type of this viewport. */ @@ -252,7 +252,7 @@ public: virtual void SetCursorString(const QString& str) = 0; virtual void SetFocus() = 0; - virtual void Invalidate(BOOL bErase = 1) = 0; + virtual void Invalidate(bool bErase = 1) = 0; // Is overridden by RenderViewport virtual void SetFOV([[maybe_unused]] float fov) {} @@ -266,8 +266,8 @@ public: void SetViewPane(CLayoutViewPane* viewPane) { m_viewPane = viewPane; } //Child classes can override these to provide extra logic that wraps - //widget rendering. Needed by the RenderViewport to handle raycasts - //from screen-space to world-space. + //widget rendering. Needed by the RenderViewport to handle raycasts + //from screen-space to world-space. virtual void PreWidgetRendering() {} virtual void PostWidgetRendering() {} @@ -346,7 +346,7 @@ public: QString GetName() const; virtual void SetFocus() { setFocus(); } - virtual void Invalidate([[maybe_unused]] BOOL bErase = 1) { update(); } + virtual void Invalidate([[maybe_unused]] bool bErase = 1) { update(); } // Is overridden by RenderViewport virtual void SetFOV([[maybe_unused]] float fov) {} diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 4d27506929..acc6771e9f 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -91,7 +91,7 @@ namespace void ViewportInfoStatusUpdated(int newIndex); private: - void OnViewportInfoDisplayStateChanged(AZ::AtomBridge::ViewportInfoDisplayState state) + void OnViewportInfoDisplayStateChanged(AZ::AtomBridge::ViewportInfoDisplayState state) override { emit ViewportInfoStatusUpdated(static_cast(state)); } diff --git a/Code/Editor/WipFeatureManager.cpp b/Code/Editor/WipFeatureManager.cpp index 6777065c1c..f6fbc7ac93 100644 --- a/Code/Editor/WipFeatureManager.cpp +++ b/Code/Editor/WipFeatureManager.cpp @@ -19,7 +19,7 @@ const char* CWipFeatureManager::kWipFeaturesFilename = "@user@\\Editor\\UI\\WipF #else const char* CWipFeatureManager::kWipFeaturesFilename = "@user@/Editor/UI/WipFeatures.xml"; #endif -CWipFeatureManager* CWipFeatureManager::s_pInstance = NULL; +CWipFeatureManager* CWipFeatureManager::s_pInstance = nullptr; static void WipFeatureVarChange(ICVar* pVar) { @@ -162,7 +162,7 @@ void CWipFeatureManager::Shutdown() { CWipFeatureManager::Instance()->Save(); delete s_pInstance; - s_pInstance = NULL; + s_pInstance = nullptr; } bool CWipFeatureManager::Load(const char* pFilename, bool bClearExisting) @@ -350,7 +350,7 @@ void CWipFeatureManager::ShowFeature(int aFeatureId, bool bShow) if (m_features[aFeatureId].m_pfnUpdateFeature) { - m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, &bShow, NULL, NULL, NULL); + m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, &bShow, nullptr, nullptr, nullptr); } } @@ -360,7 +360,7 @@ void CWipFeatureManager::EnableFeature(int aFeatureId, bool bEnable) if (m_features[aFeatureId].m_pfnUpdateFeature) { - m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, NULL, &bEnable, NULL, NULL); + m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, nullptr, &bEnable, nullptr, nullptr); } } @@ -370,7 +370,7 @@ void CWipFeatureManager::SetFeatureSafeMode(int aFeatureId, bool bSafeMode) if (m_features[aFeatureId].m_pfnUpdateFeature) { - m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, NULL, NULL, &bSafeMode, NULL); + m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, nullptr, nullptr, &bSafeMode, nullptr); } } @@ -380,7 +380,7 @@ void CWipFeatureManager::SetFeatureParams(int aFeatureId, const char* pParams) if (m_features[aFeatureId].m_pfnUpdateFeature) { - m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, NULL, NULL, NULL, pParams); + m_features[aFeatureId].m_pfnUpdateFeature(aFeatureId, nullptr, nullptr, nullptr, pParams); } } @@ -392,7 +392,7 @@ void CWipFeatureManager::ShowAllFeatures(bool bShow) if (iter->second.m_pfnUpdateFeature) { - iter->second.m_pfnUpdateFeature(iter->first, &bShow, NULL, NULL, NULL); + iter->second.m_pfnUpdateFeature(iter->first, &bShow, nullptr, nullptr, nullptr); } } } @@ -405,7 +405,7 @@ void CWipFeatureManager::EnableAllFeatures(bool bEnable) if (iter->second.m_pfnUpdateFeature) { - iter->second.m_pfnUpdateFeature(iter->first, NULL, &bEnable, NULL, NULL); + iter->second.m_pfnUpdateFeature(iter->first, nullptr, &bEnable, nullptr, nullptr); } } } @@ -418,7 +418,7 @@ void CWipFeatureManager::SetAllFeaturesSafeMode(bool bSafeMode) if (iter->second.m_pfnUpdateFeature) { - iter->second.m_pfnUpdateFeature(iter->first, NULL, NULL, &bSafeMode, NULL); + iter->second.m_pfnUpdateFeature(iter->first, nullptr, nullptr, &bSafeMode, nullptr); } } } @@ -431,7 +431,7 @@ void CWipFeatureManager::SetAllFeaturesParams(const char* pParams) if (iter->second.m_pfnUpdateFeature) { - iter->second.m_pfnUpdateFeature(iter->first, NULL, NULL, NULL, pParams); + iter->second.m_pfnUpdateFeature(iter->first, nullptr, nullptr, nullptr, pParams); } } } diff --git a/Code/Editor/WipFeatureManager.h b/Code/Editor/WipFeatureManager.h index 52ed364524..cd20f6d591 100644 --- a/Code/Editor/WipFeatureManager.h +++ b/Code/Editor/WipFeatureManager.h @@ -48,7 +48,7 @@ public: static const char* kWipFeaturesFilename; // Used to register a callback function to update the state of features whitin the editor - // pbVisible, pbEnabled, pbSafeMode, pParams - if the pointer is NULL, then that attribute was not changed + // pbVisible, pbEnabled, pbSafeMode, pParams - if the pointer is nullptr, then that attribute was not changed typedef void (* TWipFeatureUpdateCallback)(int aFeatureId, const bool* const pbVisible, const bool* const pbEnabled, const bool* const pbSafeMode, const char* pParams); // wip feature registerer auto create object, used for static auto feature creation with the REGISTER_WIP_FEATURE macro @@ -71,7 +71,7 @@ public: , m_bVisible(true) , m_bEnabled(true) , m_bSafeMode(false) - , m_pfnUpdateFeature(NULL) + , m_pfnUpdateFeature(nullptr) , m_bLoadedFromXml(false) {} diff --git a/Code/Editor/WipFeaturesDlg.cpp b/Code/Editor/WipFeaturesDlg.cpp index 8a5c323fa5..0d0a179539 100644 --- a/Code/Editor/WipFeaturesDlg.cpp +++ b/Code/Editor/WipFeaturesDlg.cpp @@ -152,7 +152,7 @@ public: } }; -CWipFeaturesDlg::CWipFeaturesDlg(QWidget* pParent /*=NULL*/) +CWipFeaturesDlg::CWipFeaturesDlg(QWidget* pParent /*=nullptr*/) : QDialog(pParent) , m_ui(new Ui::WipFeaturesDlg) { diff --git a/Code/Editor/WipFeaturesDlg.h b/Code/Editor/WipFeaturesDlg.h index 03b3654a27..28f4f43958 100644 --- a/Code/Editor/WipFeaturesDlg.h +++ b/Code/Editor/WipFeaturesDlg.h @@ -29,7 +29,7 @@ class CWipFeaturesDlg { Q_OBJECT public: - CWipFeaturesDlg(QWidget* pParent = NULL); // standard constructor + CWipFeaturesDlg(QWidget* pParent = nullptr); // standard constructor virtual ~CWipFeaturesDlg(); private: From 2f57d725611b559fe968d4f730ff4d7bd46edfe7 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Mon, 2 Aug 2021 23:50:44 -0600 Subject: [PATCH 05/18] Add initial JobGraph prototype Signed-off-by: Jeremy Ong --- .../AzCore/Jobs/Internal/JobTypeEraser.cpp | 76 ++ .../AzCore/Jobs/Internal/JobTypeEraser.h | 229 +++++ .../AzCore/AzCore/Jobs/JobDescriptor.h | 49 + .../AzCore/AzCore/Jobs/JobExecutor.cpp | 361 ++++++++ .../AzCore/AzCore/Jobs/JobExecutor.h | 86 ++ .../Framework/AzCore/AzCore/Jobs/JobGraph.cpp | 60 ++ Code/Framework/AzCore/AzCore/Jobs/JobGraph.h | 139 +++ .../Framework/AzCore/AzCore/Jobs/JobGraph.inl | 62 ++ .../AzCore/AzCore/azcore_files.cmake | 8 + .../AzCore/AzCore/std/parallel/thread.h | 3 +- Code/Framework/AzCore/Tests/JobGraphTests.cpp | 848 ++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 1 + 12 files changed, 1920 insertions(+), 2 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp create mode 100644 Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobGraph.h create mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl create mode 100644 Code/Framework/AzCore/Tests/JobGraphTests.cpp diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp new file mode 100644 index 0000000000..043f232e32 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp @@ -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 + * + */ + +#include + +namespace AZ::Internal +{ + TypeErasedJob::TypeErasedJob(TypeErasedJob&& other) noexcept + { + if (!other.m_relocator || other.m_lambda != other.m_buffer) + { + // The type-erased lambda is trivially relocatable OR, the lambda is heap allocated + memcpy(this, &other, sizeof(TypeErasedJob)); + + if (other.m_lambda == other.m_buffer) + { + m_lambda = m_buffer; + } + + // Prevent deletion in the event the lambda had spilled to the heap + other.m_lambda = nullptr; + return; + } + + // At this point, we know the lambda was inlined + m_lambda = m_buffer; + + m_invoker = other.m_invoker; + m_relocator = other.m_relocator; + m_destroyer = other.m_destroyer; + + // We now own the lambda, so clear the moved-from job's destroyer + other.m_destroyer = nullptr; + other.m_invoker = nullptr; + + m_relocator(m_buffer, other.m_buffer); + } + + TypeErasedJob& TypeErasedJob::operator=(TypeErasedJob&& other) noexcept + { + if (this == &other) + { + return *this; + } + + this->~TypeErasedJob(); + + new (this) TypeErasedJob{ AZStd::move(other) }; + + return *this; + } + + TypeErasedJob::~TypeErasedJob() + { + if (m_lambda) + { + if (m_destroyer) + { + // The presence of m_destroyer indicates that the lambda is not trivially destructible + m_destroyer(m_lambda); + } + + if (m_lambda != m_buffer) + { + // We've spilled the lambda into the heap, free its memory + azfree(m_lambda); + } + } + } + +} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h new file mode 100644 index 0000000000..1455f1311a --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h @@ -0,0 +1,229 @@ +/* + * 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 +#include + +namespace AZ::Internal +{ + using JobInvoke_t = void (*)(void* lambda); + using JobRelocate_t = void (*)(void* dst, void* src); + using JobDestroy_t = void (*)(void* obj); + + class CompiledJobGraph; + + // Lambdas are opaque types and we cannot extract any member function pointers. In order to store lambdas in a + // type erased fashion, we instead use a single function call indirection, invoking the lambda function in a + // static class function which has a stable address in memory. The Erased* methods return addresses to the + // indirect callers of the lambda copy/move assignment operators, call operator, and destructor. + // + // For lambdas that are trivially relocatable, both the returned move and copy assignment function pointers + // will be nullptr. + // + // Lambdas that are trivially destructible will result in a nullptr returned JobDestroy_t pointer. + // + // The class will check that the lambda is copy assignable or movable. + template + class JobTypeEraser final + { + public: + constexpr JobInvoke_t ErasedInvoker() + { + return reinterpret_cast(Invoker); + } + + constexpr JobRelocate_t ErasedRelocator() + { + if constexpr (AZStd::is_trivially_move_constructible_v) + { + return nullptr; + } + else if constexpr (AZStd::is_move_constructible_v) + { + return reinterpret_cast(Mover); + } + else if constexpr (AZStd::is_copy_constructible_v) + { + return reinterpret_cast(Copyer); + } + else + { + static_assert( + false, + "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " + "constructible."); + } + } + + constexpr JobDestroy_t ErasedDestroyer() + { + if constexpr (AZStd::is_trivially_destructible_v) + { + return nullptr; + } + else + { + return reinterpret_cast(Destroyer); + } + } + + private: + constexpr static void Invoker(Lambda* lambda) + { + lambda->operator()(); + } + + constexpr static void Mover(Lambda* dst, Lambda* src) + { + new (dst) Lambda{ AZStd::move(*src) }; + } + + constexpr static void Copyer(Lambda* dst, Lambda* src) + { + new (dst) Lambda{ *src }; + } + + constexpr static void Destroyer(Lambda* lambda) + { + lambda->~Lambda(); + } + }; + + // The TypeErasedJob encapsulates member function pointers to store in a homogeneously-typed container + // The function signature of all lambdas encoded in a TypeErasedJob is void(*)(). The lambdas can capture + // data, in which case the data is inlined in this structure if the payload is less than or equal to the + // buffer size. Otherwise, the data is heap allocated. + class alignas(alignof(max_align_t)) TypeErasedJob final + { + public: + // The inline buffer allows the TypeErasedJob to span two cache lines. Lambdas can capture 56 + // bytes of data (7 pointers/references on a 64-bit machine) before spilling to the heap. + constexpr static size_t BufferSize = 128 - sizeof(size_t) * 6 - sizeof(uint32_t) - sizeof(JobDescriptor); + + TypeErasedJob() = default; + + template + TypeErasedJob(JobDescriptor const& desc, Lambda&& lambda) noexcept + : m_descriptor{desc} + { + JobTypeEraser eraser; + m_invoker = eraser.ErasedInvoker(); + m_relocator = eraser.ErasedRelocator(); + m_destroyer = eraser.ErasedDestroyer(); + + // NOTE: This code is conservative in that extended alignment requirements result in a heap + // spill, even if the lambda could have occupied a portion of the inline buffer with a base + // pointer adjustment. + if constexpr (sizeof(Lambda) <= BufferSize && alignof(Lambda) <= alignof(max_align_t)) + { + TypedRelocate(AZStd::forward(lambda), m_buffer); + m_lambda = m_buffer; + } + else + { + // Lambda has spilled to the heap (or requires extended alignment) + m_lambda = reinterpret_cast(azmalloc(sizeof(Lambda), alignof(Lambda))); + TypedRelocate(AZStd::forward(lambda), m_lambda); + } + } + + TypeErasedJob(TypeErasedJob&& other) noexcept; + + TypeErasedJob& operator=(TypeErasedJob&& other) noexcept; + + ~TypeErasedJob(); + + void Link(TypeErasedJob& other); + + // Indicates if this job is a root of the graph (with no dependencies) + bool IsRoot(); + + void AttachToJobGraph(CompiledJobGraph& graph) noexcept + { + m_graph = &graph; + } + + void Invoke() + { + m_invoker(m_lambda); + } + + uint8_t GetPriorityNumber() const + { + return static_cast(m_descriptor.priority); + } + + private: + friend class CompiledJobGraph; + friend class JobWorker; + + // This relocation avoids branches needed if the lambda type is unknown + template + void TypedRelocate(Lambda&& lambda, char* destination) + { + if constexpr (AZStd::is_trivially_move_constructible_v) + { + memcpy(destination, reinterpret_cast(&lambda), sizeof(Lambda)); + } + else if constexpr (AZStd::is_move_constructible_v) + { + new (destination) Lambda{ AZStd::move(lambda) }; + } + else if constexpr (AZStd::is_copy_constructible_v) + { + new (destination) Lambda{ lambda }; + } + else + { + static_assert( + false, + "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " + "constructible."); + } + } + + // Small buffer optimization for lambdas. We cover our bases here by enforcing alignment on the + // class to equal the alignment of the largest scalar type available on the system (generally + // 16 bytes). + char m_buffer[BufferSize]; + + // This value is an offset in a buffer that stores dependency tracking information. + uint32_t m_successorOffset = 0; + uint32_t m_inboundLinkCount = 0; + uint32_t m_outboundLinkCount = 0; + + // May point to the inlined payload buffer, or heap + char* m_lambda = nullptr; + + CompiledJobGraph* m_graph = nullptr; + + JobInvoke_t m_invoker; + + // If nullptr, the lambda is trivially relocatable (via memcpy). Otherwise, it must be invoked + // when instances of this class are moved. + JobRelocate_t m_relocator; + JobDestroy_t m_destroyer; + + JobDescriptor m_descriptor; + }; + + inline void TypeErasedJob::Link(TypeErasedJob& other) + { + ++m_outboundLinkCount; + ++other.m_inboundLinkCount; + } + + inline bool TypeErasedJob::IsRoot() + { + return m_inboundLinkCount == 0; + } +} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h b/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h new file mode 100644 index 0000000000..82a9603bd5 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h @@ -0,0 +1,49 @@ +/* + * 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 + +namespace AZ +{ + // Job priorities MAY be used judiciously to fine tune runtime execution, with the understanding + // that profiling is needed to understand what the critical path per frame is. Modifying + // job priorities is an EXPERT setting that should succeed a healthy dose of measurement. + enum class JobPriority : uint8_t + { + CRITICAL = 0, + HIGH = 1, + MEDIUM = 2, // Default + LOW = 3, + PRIORITY_COUNT = 4, + }; + + // All submitted jobs are associated with a JobDescriptor which defines the priority, affinitization, + // and tracking of the job resource utilization. + // + // TODO: Define various job kinds and provide a mechanism for cpuMask computation on different systems. + struct JobDescriptor + { + // Unique job kind label (e.g. "frustum culling") + // Job names *must* be provided + const char* jobName = nullptr; + + // Associates a set of job kinds together for budget tracking (e.g. "graphics") + const char* jobGroup = nullptr; + + // EXPERTS ONLY. Jobs of higher priority are executed ahead of any lower priority jobs + // that were queued before it provided they had not yet started + JobPriority priority = JobPriority::MEDIUM; + + // EXPERTS ONLY. A bitmask that restricts jobs of this kind to run only on cores + // corresponding to a set bit. 0 is synonymous with all bits set + uint32_t cpuMask = 0; + }; +} diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp new file mode 100644 index 0000000000..16e4983752 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp @@ -0,0 +1,361 @@ +/* + * 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 +#include +#include +#include +#include + +#include + +namespace AZ +{ + constexpr static size_t PRIORITY_COUNT = static_cast(JobPriority::PRIORITY_COUNT); + + namespace Internal + { + CompiledJobGraph::CompiledJobGraph( + AZStd::vector&& jobs, + AZStd::unordered_map>& links, + size_t linkCount, + bool retained) + : m_remaining{ jobs.size() } + , m_retained{ retained } + { + m_jobs = AZStd::move(jobs); + m_dependencyCounts = reinterpret_cast*>(azcalloc(sizeof(AZStd::atomic) * m_jobs.size())); + m_successors.resize(linkCount); + + uint32_t* cursor = m_successors.data(); + + for (size_t i = 0; i != m_jobs.size(); ++i) + { + TypeErasedJob& job = m_jobs[i]; + job.m_successorOffset = cursor - m_successors.data(); + cursor += job.m_outboundLinkCount; + + AZ_Assert(job.m_outboundLinkCount == links[i].size(), "Job outbound link information mismatch"); + + for (uint32_t j = 0; j != job.m_outboundLinkCount; ++j) + { + m_successors[static_cast(job.m_successorOffset) + j] = links[i][j]; + } + + if (job.m_inboundLinkCount > 0) + { + m_dependencyCounts[i].store(job.m_inboundLinkCount, AZStd::memory_order_release); + } + } + + // TODO: Check for dependency cycles + } + + CompiledJobGraph::~CompiledJobGraph() + { + if (m_dependencyCounts) + { + azfree(m_dependencyCounts); + } + } + + void CompiledJobGraph::Release() + { + if (--m_remaining == 0) + { + if (m_retained) + { + m_remaining = m_jobs.size(); + for (size_t i = 0; i != m_jobs.size(); ++i) + { + TypeErasedJob& job = m_jobs[i]; + if (job.m_inboundLinkCount > 0) + { + m_dependencyCounts[i].store(job.m_inboundLinkCount, AZStd::memory_order_release); + } + } + } + + if (m_waitEvent) + { + m_waitEvent->m_submitted = false; + m_waitEvent->Signal(); + } + + if (!m_retained) + { + azdestroy(this); + } + } + } + + struct QueueStatus + { + AZStd::atomic head; + AZStd::atomic tail; + AZStd::atomic reserve; + }; + + // The Job Queue is a lock free 4-priority queue. Its basic operation is as follows: + // Each priority level is associated with a different queue, corresponding to the maximum size of a uint16_t. + // Each queue is implemented as a ring buffer, and a 64 bit atomic maintains the following state per queue: + // - offset to the "head" of the ring, from where we acquire elements + // - offset to the "tail" of the ring, which tracks where new elements should be enqueued + // - offset to a tail reservation index, which is used to reserve a slot to enqueue elements + class JobQueue final + { + public: + // Preallocating upfront allows us to reserve slots to insert jobs without locks. + // Each thread allocated by the job manager consumes ~2 MB. + constexpr static uint16_t MaxQueueSize = 0xffff; + constexpr static uint8_t PriorityLevelCount = static_cast(JobPriority::PRIORITY_COUNT); + + JobQueue() = default; + JobQueue(const JobQueue&) = delete; + JobQueue& operator=(const JobQueue&) = delete; + + bool Enqueue(TypeErasedJob* job); + TypeErasedJob* TryDequeue(); + + private: + QueueStatus m_status[PriorityLevelCount] = {}; + TypeErasedJob* m_queues[PriorityLevelCount][MaxQueueSize] = {}; + }; + + bool JobQueue::Enqueue(TypeErasedJob* job) + { + uint8_t priority = job->GetPriorityNumber(); + QueueStatus& status = m_status[priority]; + + while (true) + { + uint16_t reserve = status.reserve.load(); + uint16_t head = status.head.load(); + + // Enqueuing is done in two phases because we cannot atomically write the job to the slot we reserve + // and simulataneously publish the fact that the slot is now available. + if (reserve != head - 1) + { + // Try to reserve a slot + if (status.reserve.compare_exchange_weak(reserve, reserve + 1)) + { + m_queues[priority][reserve] = job; + + uint16_t expectedReserve = reserve; + + // Increment the tail to advertise the new job + while (!status.tail.compare_exchange_weak(expectedReserve, reserve + 1)) + { + expectedReserve = reserve; + } + + return status.head == status.tail - 1; + } + + // We failed to reserve a slot, try again + } + else + { + // TODO need exponential backup here + AZStd::this_thread::sleep_for(AZStd::chrono::microseconds{ 100 }); + } + } + } + + TypeErasedJob* JobQueue::TryDequeue() + { + for (size_t priority = 0; priority != PriorityLevelCount; ++priority) + { + QueueStatus& status = m_status[priority]; + while (true) + { + uint16_t head = status.head.load(); + uint16_t tail = status.tail.load(); + if (head == tail) + { + // Queue empty + break; + } + else + { + TypeErasedJob* job = m_queues[priority][status.head]; + if (status.head.compare_exchange_weak(head, head + 1)) + { + return job; + } + } + } + } + + return nullptr; + } + + class JobWorker + { + public: + void Spawn(::AZ::JobExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize) + { + m_executor = &executor; + + AZStd::string threadName = AZStd::string::format("JobWorker %zu", id); + AZStd::thread_desc desc = {}; + desc.m_name = threadName.c_str(); + if (affinitize) + { + desc.m_cpuId = 1 << id; + } + m_active.store(true, AZStd::memory_order_release); + + m_thread = AZStd::thread{ [this, &initSemaphore] + { + initSemaphore.release(); + Run(); + }, + &desc }; + } + + void Join() + { + m_active.store(false, AZStd::memory_order_release); + m_semaphore.release(); + m_thread.join(); + } + + void Enqueue(TypeErasedJob* job) + { + if (m_queue.Enqueue(job)) + { + // The queue was empty prior to enqueueing the job, release the semaphore + m_semaphore.release(); + } + } + + private: + void Run() + { + while (m_active) + { + m_semaphore.acquire(); + // m_semaphore.try_acquire_for(AZStd::chrono::microseconds{ 10 }); + + if (!m_active) + { + return; + } + + TypeErasedJob* job = m_queue.TryDequeue(); + while (job) + { + job->Invoke(); + // Decrement counts for all job successors + for (size_t j = 0; j != job->m_outboundLinkCount; ++j) + { + uint32_t successorIndex = job->m_graph->m_successors[job->m_successorOffset + j]; + if (--job->m_graph->m_dependencyCounts[successorIndex] == 0) + { + m_executor->Submit(job->m_graph->m_jobs[successorIndex]); + } + } + + job->m_graph->Release(); + --m_executor->m_remaining; + + job = m_queue.TryDequeue(); + } + } + } + + AZStd::thread m_thread; + AZStd::atomic m_active; + AZStd::binary_semaphore m_semaphore; + + ::AZ::JobExecutor* m_executor; + JobQueue m_queue; + }; + } // namespace Internal + + JobExecutor& JobExecutor::Instance() + { + // TODO: Create the default executor as part of a component (as in JobManagerComponent) + static JobExecutor executor; + return executor; + } + + JobExecutor::JobExecutor(uint32_t threadCount) + { + // TODO: Configure thread count + affinity based on configuration + m_threadCount = threadCount == 0 ? AZStd::thread::hardware_concurrency() : threadCount; + + m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::JobWorker))); + + bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency(); + + AZStd::semaphore initSemaphore; + + for (size_t i = 0; i != m_threadCount; ++i) + { + new (m_workers + i) Internal::JobWorker{}; + m_workers[i].Spawn(*this, i, initSemaphore, affinitize); + } + + for (size_t i = 0; i != m_threadCount; ++i) + { + initSemaphore.acquire(); + } + } + + JobExecutor::~JobExecutor() + { + for (size_t i = 0; i != m_threadCount; ++i) + { + m_workers[i].Join(); + m_workers[i].~JobWorker(); + } + + azfree(m_workers); + } + + void JobExecutor::Submit(Internal::CompiledJobGraph& graph) + { + for (Internal::TypeErasedJob& job : graph.Jobs()) + { + job.AttachToJobGraph(graph); + } + + // Submit all jobs that have no inbound edges + for (Internal::TypeErasedJob& job : graph.Jobs()) + { + if (job.IsRoot()) + { + Submit(job); + } + } + } + + void JobExecutor::Submit(Internal::TypeErasedJob& job) + { + // TODO: Something more sophisticated is likely needed here. + // First, we are completely ignoring affinity. + // Second, some heuristics on core availability will help distribute work more effectively + ++m_remaining; + m_workers[++m_lastSubmission % m_threadCount].Enqueue(&job); + } + + void JobExecutor::Drain() + { + while (m_remaining > 0) + { + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds{ 100 }); + } + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h new file mode 100644 index 0000000000..9418126678 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h @@ -0,0 +1,86 @@ +/* + * 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 +#include +#include + +namespace AZ +{ + class JobGraphEvent; + + namespace Internal + { + class CompiledJobGraph final + { + public: + AZ_CLASS_ALLOCATOR(CompiledJobGraph, SystemAllocator, 0) + + CompiledJobGraph( + AZStd::vector&& jobs, + AZStd::unordered_map>& links, + size_t linkCount, + bool retained); + + ~CompiledJobGraph(); + + AZStd::vector& Jobs() noexcept + { + return m_jobs; + } + + // Indicate that a constituent job has finished and decrement a counter to determine if the + // graph should be freed + void Release(); + + private: + friend class JobGraph; + friend class JobWorker; + + AZStd::vector m_jobs; + AZStd::vector m_successors; + AZStd::atomic* m_dependencyCounts = nullptr; + JobGraphEvent* m_waitEvent = nullptr; + AZStd::atomic m_remaining; + bool m_retained; + }; + + class JobWorker; + } // namespace Internal + + class JobExecutor + { + public: + AZ_CLASS_ALLOCATOR(JobExecutor, SystemAllocator, 0); + + static JobExecutor& Instance(); + + // Passing 0 for the threadCount requests for the thread count to match the hardware concurrency + JobExecutor(uint32_t threadCount = 0); + ~JobExecutor(); + + void Submit(Internal::CompiledJobGraph& graph); + + void Submit(Internal::TypeErasedJob& job); + + // Busy wait until jobs are cleared from the executor (note, does not prevent future jobs from being submitted) + void Drain(); + private: + friend class Internal::JobWorker; + + Internal::JobWorker* m_workers; + uint32_t m_threadCount = 0; + AZStd::atomic m_lastSubmission; + AZStd::atomic m_remaining; + }; +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp new file mode 100644 index 0000000000..b715e0ada7 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp @@ -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 + * + */ + +#include + +#include + +namespace AZ +{ + using Internal::CompiledJobGraph; + + void JobToken::PrecedesInternal(JobToken& comesAfter) + { + AZ_Assert(!m_parent.m_submitted, "Cannot mutate a JobGraph that was previously submitted."); + + // Increment inbound/outbound edge counts + m_parent.m_jobs[m_index].Link(m_parent.m_jobs[comesAfter.m_index]); + + m_parent.m_links[m_index].emplace_back(comesAfter.m_index); + + ++m_parent.m_linkCount; + } + + JobGraph::~JobGraph() + { + if (m_retained && m_compiledJobGraph) + { + azdestroy(m_compiledJobGraph); + } + } + + void JobGraph::Submit(JobGraphEvent* waitEvent) + { + SubmitOnExecutor(JobExecutor::Instance(), waitEvent); + } + + void JobGraph::SubmitOnExecutor(JobExecutor& executor, JobGraphEvent* waitEvent) + { + m_submitted = true; + + if (!m_compiledJobGraph) + { + m_compiledJobGraph = aznew CompiledJobGraph(AZStd::move(m_jobs), m_links, m_linkCount, m_retained); + } + + m_compiledJobGraph->m_waitEvent = waitEvent; + + executor.Submit(*m_compiledJobGraph); + + if (waitEvent) + { + waitEvent->m_submitted = true; + } + } +} diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h new file mode 100644 index 0000000000..62565ea78c --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h @@ -0,0 +1,139 @@ +/* + * 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 + +// NOTE: If adding additional header/symbol dependencies, consider if such additions are better +// suited in the private CompiledJobGraph implementation instead to keep this header lean. +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Internal + { + class CompiledJobGraph; + } + class JobExecutor; + + // A JobToken is returned each time a Job is added to the JobGraph. JobTokens are used to + // express dependencies between jobs within the graph. + class JobToken final + { + public: + // Indicate that this job must finish before the job passed as the argument + template + void Precedes(JT&... tokens); + + private: + friend class JobGraph; + + void PrecedesInternal(JobToken& comesAfter); + + // Only the JobGraph should be creating JobToken + JobToken(JobGraph& parent, size_t index); + + JobGraph& m_parent; + size_t m_index; + }; + + // A JobGraphEvent may be used to block until a job graph has finished executing. Usage + // is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting + // the graph without synchronization over the course of the frame). However, the event + // is useful for the edges of the computation graph. + // + // You are responsible for ensuring the event object lifetime exceeds the job graph lifetime. + // + // After the JobGraphEvent is signaled, you are allowed to reuse the same JobGraphEvent + // for a future submission. + class JobGraphEvent + { + public: + bool IsSignaled(); + void Wait(); + + private: + friend class ::AZ::Internal::CompiledJobGraph; + friend class JobGraph; + void Signal(); + + AZStd::binary_semaphore m_semaphore; + bool m_submitted = false; + }; + + // The JobGraph encapsulates a set of jobs and their interdependencies. After adding + // jobs, and marking dependencies as necessary, the entire graph is submitted via + // the JobGraph::Submit method. + // + // The JobGraph MAY be retained across multiple frames and resubmitted, provided the + // user provides some guarantees (see comments associated with JobGraph::Retain). + class JobGraph final + { + public: + ~JobGraph(); + + // Add a job to the graph, retrieiving a token that can be used to express dependencies + // between jobs. The first argument specifies the JobKind, used for tracking the job. + template + JobToken AddJob(JobDescriptor const& descriptor, Lambda&& lambda); + + template + AZStd::fixed_vector AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas); + + // By default, you are responsible for retaining the JobGraph, indicating you promise that + // this JobGraph will live as long as it takes for all constituent jobs to complete. + // Once retained, this job graph can be resubmitted after completion without any + // modifications. JobTokens that were created as a result of adding jobs used to + // mark dependencies DO NOT need to outlive the job graph. + // + // Invoking Detach PRIOR to submission indicates you wish the jobs associated with this + // JobGraph to deallocate upon completion. After invoking Detach, you may let this JobGraph + // go out of scope or deallocate after submission. + // + // NOTE: The JobGraph has no concept of resources used by design. Resubmission + // of the job graph is expected to rely on either indirection, or safe overwriting + // of previously used memory to supply new data (this can even be done as the first + // job in the graph). + void Detach(); + + // Invoke the job graph, asserting if there are dependency violations. Note that + // submitting the same graph multiple times to process simultaneously is VALID + // behavior. This is, for example, a mechanism that allows a job graph to loop + // in perpetuity (in fact, the entire frame could be modeled as a single job graph, + // where the final job resubmits the job graph again). + // + // This API is not designed to protect against memory safety violations (nothing + // can prevent a user from incorrectly aliasing memory unsafely even without repeated + // submission). To catch memory safety violations, it is ENCOURAGED that you access + // data through JobResource handles. + void Submit(JobGraphEvent* waitEvent = nullptr); + + // Same as submit but run on a different executor than the default system executor + void SubmitOnExecutor(JobExecutor& executor, JobGraphEvent* waitEvent = nullptr); + + private: + friend class JobToken; + + Internal::CompiledJobGraph* m_compiledJobGraph = nullptr; + + AZStd::vector m_jobs; + + // Job index |-> Dependent job indices + AZStd::unordered_map> m_links; + + uint32_t m_linkCount = 0; + bool m_retained = true; + bool m_submitted = false; + }; +} // namespace AZ + +#include diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl new file mode 100644 index 0000000000..f541d9923f --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl @@ -0,0 +1,62 @@ +/* + * 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 + +namespace AZ +{ + inline JobToken::JobToken(JobGraph& parent, size_t index) + : m_parent{ parent } + , m_index{ index } + { + } + + template + inline void JobToken::Precedes(JT&... tokens) + { + (PrecedesInternal(tokens), ...); + } + + inline bool JobGraphEvent::IsSignaled() + { + AZ_Assert(m_submitted, "Querying the status of a job graph event that was never submitted along with the jobgraph"); + return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 }); + } + + inline void JobGraphEvent::Wait() + { + AZ_Assert(m_submitted, "Waiting on a job graph event that was never submitted along with the jobgraph"); + m_semaphore.acquire(); + } + + inline void JobGraphEvent::Signal() + { + m_semaphore.release(); + } + + template + inline JobToken JobGraph::AddJob(JobDescriptor const& desc, Lambda&& lambda) + { + AZ_Assert(!m_submitted, "Cannot mutate a JobGraph that was previously submitted."); + + m_jobs.emplace_back(desc, AZStd::forward(lambda)); + + return { *this, m_jobs.size() - 1 }; + } + + template + inline AZStd::fixed_vector AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas) + { + return { AddJob(descriptor, lambdas)... }; + } + + inline void JobGraph::Detach() + { + m_retained = false; + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index e3d2987a3c..a23ec9ab82 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -221,6 +221,8 @@ set(FILES Jobs/Internal/JobManagerWorkStealing.cpp Jobs/Internal/JobManagerWorkStealing.h Jobs/Internal/JobNotify.h + Jobs/Internal/JobTypeEraser.cpp + Jobs/Internal/JobTypeEraser.h Jobs/Job.cpp Jobs/Job.h Jobs/JobCancelGroup.h @@ -228,8 +230,14 @@ set(FILES Jobs/JobCompletionSpin.h Jobs/JobContext.cpp Jobs/JobContext.h + Jobs/JobDescriptor.h Jobs/JobEmpty.h + Jobs/JobExecutor.cpp + Jobs/JobExecutor.h Jobs/JobFunction.h + Jobs/JobGraph.cpp + Jobs/JobGraph.h + Jobs/JobGraph.inl Jobs/JobManager.cpp Jobs/JobManager.h Jobs/JobManagerBus.h diff --git a/Code/Framework/AzCore/AzCore/std/parallel/thread.h b/Code/Framework/AzCore/AzCore/std/parallel/thread.h index a46671a4cd..9f7830c91b 100644 --- a/Code/Framework/AzCore/AzCore/std/parallel/thread.h +++ b/Code/Framework/AzCore/AzCore/std/parallel/thread.h @@ -69,8 +69,7 @@ namespace AZStd int m_priority{ -100000 }; //! The CPU ids (as a bitfield) that this thread will be running on, see \ref AZStd::thread_desc::m_cpuId. - //! Windows: This parameter is ignored. - //! On other platforms, each bit maps directly to the core numbers [0-n], default is 0 + //! Each bit maps directly to the core numbers [0-n], default is 0 int m_cpuId{ AFFINITY_MASK_ALL }; //! If we can join the thread. diff --git a/Code/Framework/AzCore/Tests/JobGraphTests.cpp b/Code/Framework/AzCore/Tests/JobGraphTests.cpp new file mode 100644 index 0000000000..175881b89a --- /dev/null +++ b/Code/Framework/AzCore/Tests/JobGraphTests.cpp @@ -0,0 +1,848 @@ +/* + * 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 + +using AZ::JobDescriptor; +using AZ::JobGraph; +using AZ::JobGraphEvent; +using AZ::JobExecutor; +using AZ::Internal::TypeErasedJob; +using AZ::JobPriority; + +static JobDescriptor defaultJD{ "JobGraphTestJob", "JobGraphTests" }; + +namespace UnitTest +{ + class JobGraphTestFixture : public AllocatorsTestFixture + { + public: + void SetUp() override + { + AllocatorsTestFixture::SetUp(); + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + m_executor = aznew JobExecutor(4); + } + + void TearDown() override + { + azdestroy(m_executor); + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + AllocatorsTestFixture::TearDown(); + } + + protected: + JobExecutor* m_executor; + }; + + TEST(JobGraphTests, TrivialJobLambda) + { + int x = 0; + + TypeErasedJob job( + defaultJD, + [&x]() + { + ++x; + }); + job.Invoke(); + + EXPECT_EQ(1, x); + } + + TEST(JobGraphTests, TrivialJobLambdaMove) + { + int x = 0; + + TypeErasedJob job( + defaultJD, + [&x]() + { + ++x; + }); + + TypeErasedJob job2 = AZStd::move(job); + + job2.Invoke(); + + EXPECT_EQ(1, x); + } + + struct TrackMoves + { + TrackMoves() = default; + + TrackMoves(const TrackMoves&) = delete; + + TrackMoves(TrackMoves&& other) + : moveCount{other.moveCount + 1} + { + } + + int moveCount = 0; + }; + + struct TrackCopies + { + TrackCopies() = default; + + TrackCopies(TrackCopies&&) = delete; + + TrackCopies(const TrackCopies& other) + : copyCount{other.copyCount + 1} + { + } + + int copyCount = 0; + }; + + TEST(JobGraphTests, MoveOnlyJobLambda) + { + TrackMoves tm; + int moveCount = 0; + + TypeErasedJob job( + defaultJD, + [tm = AZStd::move(tm), &moveCount] + { + moveCount = tm.moveCount; + }); + job.Invoke(); + + // Two moves are expected. Once into the capture body of the lambda, once to construct + // the type erased job + EXPECT_EQ(2, moveCount); + } + + TEST(JobGraphTests, MoveOnlyJobLambdaMove) + { + TrackMoves tm; + int moveCount = 0; + + TypeErasedJob job( + defaultJD, + [tm = AZStd::move(tm), &moveCount] + { + moveCount = tm.moveCount; + }); + + TypeErasedJob job2 = AZStd::move(job); + job2.Invoke(); + + EXPECT_EQ(3, moveCount); + } + + TEST(JobGraphTests, CopyOnlyJobLambda) + { + TrackCopies tc; + int copyCount = 0; + + TypeErasedJob job( + defaultJD, + [tc, ©Count] + { + copyCount = tc.copyCount; + }); + job.Invoke(); + + // Two copies are expected. Once into the capture body of the lambda, once to construct + // the type erased job + EXPECT_EQ(2, copyCount); + } + + TEST(JobGraphTests, CopyOnlyJobLambdaMove) + { + TrackCopies tc; + int copyCount = 0; + + TypeErasedJob job( + defaultJD, + [tc, ©Count] + { + copyCount = tc.copyCount; + }); + TypeErasedJob job2 = AZStd::move(job); + job2.Invoke(); + + EXPECT_EQ(3, copyCount); + } + + TEST(JobGraphTests, DestroyLambda) + { + // This test ensures that for a lambda with a destructor, the destructor is invoked + // exactly once on a non-moved-from object. + int x = 0; + struct TrackDestroy + { + TrackDestroy(int* px) + : count{ px } + { + } + TrackDestroy(TrackDestroy&& other) + : count{ other.count } + { + other.count = nullptr; + } + ~TrackDestroy() + { + if (count) + { + ++*count; + } + } + int* count = nullptr; + }; + + { + TrackDestroy td{ &x }; + TypeErasedJob job( + defaultJD, + [td = AZStd::move(td)] + { + }); + job.Invoke(); + // Destructor should not have run yet (except on moved-from instances) + EXPECT_EQ(x, 0); + } + + // Destructor should have run now + EXPECT_EQ(x, 1); + } + + TEST_F(JobGraphTestFixture, SerialGraph) + { + int x = 0; + + JobGraph graph; + auto a = graph.AddJob( + defaultJD, + [&] + { + x += 3; + }); + auto b = graph.AddJob( + defaultJD, + [&] + { + x = 4 * x; + }); + auto c = graph.AddJob( + defaultJD, + [&] + { + x -= 1; + }); + + a.Precedes(b); + b.Precedes(c); + + JobGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(11, x); + } + + TEST_F(JobGraphTestFixture, DetachedGraph) + { + int x = 0; + + JobGraphEvent ev; + + { + JobGraph graph; + auto a = graph.AddJob( + defaultJD, + [&] + { + x += 3; + }); + auto b = graph.AddJob( + defaultJD, + [&] + { + x = 4 * x; + }); + auto c = graph.AddJob( + defaultJD, + [&] + { + x -= 1; + }); + + a.Precedes(b); + b.Precedes(c); + graph.Detach(); + graph.SubmitOnExecutor(*m_executor, &ev); + } + + ev.Wait(); + + EXPECT_EQ(11, x); + } + + TEST_F(JobGraphTestFixture, ForkJoin) + { + AZStd::atomic x = 0; + + // Job a initializes x to 3 + // Job b and c toggles the lowest two bits atomically + // Job d decrements x + + JobGraph graph; + auto a = graph.AddJob( + defaultJD, + [&] + { + x = 0b111; + }); + auto b = graph.AddJob( + defaultJD, + [&] + { + x ^= 1; + }); + auto c = graph.AddJob( + defaultJD, + [&] + { + x ^= 2; + }); + auto d = graph.AddJob( + defaultJD, + [&] + { + x -= 1; + }); + + // a <-- Root + // / \ + // b c + // \ / + // d + + a.Precedes(b, c); + b.Precedes(d); + c.Precedes(d); + + JobGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(3, x); + } + + TEST_F(JobGraphTestFixture, SpawnSubgraph) + { + AZStd::atomic x = 0; + + JobGraph graph; + auto a = graph.AddJob( + defaultJD, + [&] + { + x = 0b111; + }); + auto b = graph.AddJob( + defaultJD, + [&] + { + x ^= 1; + }); + auto c = graph.AddJob( + defaultJD, + [&] + { + x ^= 2; + + JobGraph subgraph; + auto e = subgraph.AddJob( + defaultJD, + [&] + { + x ^= 0b1000; + }); + auto f = subgraph.AddJob( + defaultJD, + [&] + { + x ^= 0b10000; + }); + auto g = subgraph.AddJob( + defaultJD, + [&] + { + x += 0b1000; + }); + e.Precedes(g); + f.Precedes(g); + JobGraphEvent ev; + subgraph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + }); + auto d = graph.AddJob( + defaultJD, + [&] + { + x -= 1; + }); + + // NOTE: The ideal way to express this topology is without the wait on the subgraph + // at task g, but this is more an illustrative test. Better is to express the entire + // graph in a single larger graph. + // a <-- Root + // / \ + // b c - f + // \ \ \ + // \ e - g + // \ / + // \ / + // \ / + // d + + a.Precedes(b); + a.Precedes(c); + b.Precedes(d); + c.Precedes(d); + + JobGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(3 | 0b100000, x); + } + + TEST_F(JobGraphTestFixture, RetainedGraph) + { + AZStd::atomic x = 0; + + JobGraph graph; + auto a = graph.AddJob( + defaultJD, + [&] + { + x = 0b111; + }); + auto b = graph.AddJob( + defaultJD, + [&] + { + x ^= 1; + }); + auto c = graph.AddJob( + defaultJD, + [&] + { + x ^= 2; + }); + auto d = graph.AddJob( + defaultJD, + [&] + { + x -= 1; + }); + auto e = graph.AddJob( + defaultJD, + [&] + { + x ^= 0b1000; + }); + auto f = graph.AddJob( + defaultJD, + [&] + { + x ^= 0b10000; + }); + auto g = graph.AddJob( + defaultJD, + [&] + { + x += 0b1000; + }); + + // a <-- Root + // / \ + // b c - f + // \ \ \ + // \ e - g + // \ / + // \ / + // \ / + // d + + a.Precedes(b, c); + b.Precedes(d); + c.Precedes(e, f); + e.Precedes(g); + f.Precedes(g); + g.Precedes(d); + + JobGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(3 | 0b100000, x); + x = 0; + + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(3 | 0b100000, x); + } +} // namespace UnitTest + +#if defined(HAVE_BENCHMARK) +namespace Benchmark +{ + class JobGraphBenchmarkFixture : public ::benchmark::Fixture + { + public: + static const int32_t LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1; + static const int32_t MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1024; + static const int32_t HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1048576; + + static const int32_t SMALL_NUMBER_OF_JOBS = 10; + static const int32_t MEDIUM_NUMBER_OF_JOBS = 1024; + static const int32_t LARGE_NUMBER_OF_JOBS = 16384; + static AZStd::atomic s_numIncompleteJobs; + + int m_depth = 1; + JobGraph* graphs; + + void SetUp(benchmark::State&) override + { + s_numIncompleteJobs = 0; + + m_executor = aznew JobExecutor(0); + graphs = new JobGraph[4]; + + // Generate some random priorities + m_randomPriorities.resize(LARGE_NUMBER_OF_JOBS); + std::mt19937_64 randomPriorityGenerator(1); // Always use the same seed + std::uniform_int_distribution<> randomPriorityDistribution(0, static_cast(AZ::JobPriority::PRIORITY_COUNT)); + std::generate( + m_randomPriorities.begin(), m_randomPriorities.end(), + [&randomPriorityDistribution, &randomPriorityGenerator]() + { + return randomPriorityDistribution(randomPriorityGenerator); + }); + + // Generate some random depths + m_randomDepths.resize(LARGE_NUMBER_OF_JOBS); + std::mt19937_64 randomDepthGenerator(1); // Always use the same seed + std::uniform_int_distribution<> randomDepthDistribution( + LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + std::generate( + m_randomDepths.begin(), m_randomDepths.end(), + [&randomDepthDistribution, &randomDepthGenerator]() + { + return randomDepthDistribution(randomDepthGenerator); + }); + + for (size_t i = 0; i != 4; ++i) + { + graphs[i].AddJob( + descriptors[i], + [this] + { + benchmark::DoNotOptimize(CalculatePi(m_depth)); + --s_numIncompleteJobs; + }); + } + } + + void TearDown(benchmark::State&) override + { + delete[] graphs; + azdestroy(m_executor); + m_randomDepths = {}; + m_randomPriorities = {}; + } + + JobDescriptor descriptors[4] = { { "critical", "benchmark", JobPriority::CRITICAL }, + { "high", "benchmark", JobPriority::HIGH }, + { "mediium", "benchmark", JobPriority::MEDIUM }, + { "low", "benchmark", JobPriority::LOW } }; + + static inline double CalculatePi(AZ::u32 depth) + { + double pi = 0.0; + for (AZ::u32 i = 0; i < depth; ++i) + { + const double numerator = static_cast(((i % 2) * 2) - 1); + const double denominator = static_cast((2 * i) - 1); + pi += numerator / denominator; + } + return (pi - 1.0) * 4; + } + + void RunCalculatePiJob(int32_t depth, int8_t priority) + { + m_depth = depth; + ++s_numIncompleteJobs; + + graphs[priority].SubmitOnExecutor(*m_executor); + } + + void RunMultipleCalculatePiJobsWithDefaultPriority(uint32_t numberOfJobs, int32_t depth) + { + for (size_t i = 0; i != numberOfJobs; ++i) + { + RunCalculatePiJob(depth, 2); + } + + while (s_numIncompleteJobs > 0) + { + } + } + + void RunMultipleCalculatePiJobsWithRandomPriority(uint32_t numberOfJobs, int32_t depth) + { + for (size_t i = 0; i != numberOfJobs; ++i) + { + RunCalculatePiJob(depth, m_randomPriorities[i]); + } + + while (s_numIncompleteJobs > 0) + { + } + } + + void RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(uint32_t numberOfJobs) + { + for (size_t i = 0; i != numberOfJobs; ++i) + { + RunCalculatePiJob(m_randomDepths[i], 0); + } + + while (s_numIncompleteJobs > 0) + { + } + } + + void RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(uint32_t numberOfJobs) + { + for (size_t i = 0; i != numberOfJobs; ++i) + { + RunCalculatePiJob(m_randomDepths[i], m_randomPriorities[i]); + } + + while (s_numIncompleteJobs > 0) + { + } + } + + JobExecutor* m_executor; + AZStd::vector m_randomDepths; + AZStd::vector m_randomPriorities; + }; + + AZStd::atomic JobGraphBenchmarkFixture::s_numIncompleteJobs = 0; + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(SMALL_NUMBER_OF_JOBS); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(MEDIUM_NUMBER_OF_JOBS); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(LARGE_NUMBER_OF_JOBS); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(SMALL_NUMBER_OF_JOBS); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(MEDIUM_NUMBER_OF_JOBS); + } + } + + BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) + { + for (auto _ : state) + { + RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(LARGE_NUMBER_OF_JOBS); + } + } +} // namespace Benchmark +#endif diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index d340173c87..480baabe7a 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -40,6 +40,7 @@ set(FILES Interface.cpp IO/Path/PathTests.cpp IPC.cpp + JobGraphTests.cpp Jobs.cpp JSON.cpp FixedWidthIntegers.cpp From d1c06e9c804bbaee2e098fcf4f5610679a9f12a9 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Tue, 3 Aug 2021 23:37:56 -0600 Subject: [PATCH 06/18] Add JobGraph::Reset, streamline execution, address feedback Also, came up with more useful benchmarks that actually measure the enqueue/dequeue operations for various simple workflows. For retained graphs, time-of-flight from submission to execution is ~1us per job, indicating job granularity should be >20us for retained jobs. For dynamic jobs, where we need to pay the cost of allocation, a granularity of ~100+ us may be advised. Signed-off-by: Jeremy Ong --- .../AzCore/Jobs/Internal/JobTypeEraser.h | 19 +- .../AzCore/AzCore/Jobs/JobExecutor.cpp | 87 ++--- .../AzCore/AzCore/Jobs/JobExecutor.h | 15 +- .../Framework/AzCore/AzCore/Jobs/JobGraph.cpp | 37 +- Code/Framework/AzCore/AzCore/Jobs/JobGraph.h | 20 +- .../Framework/AzCore/AzCore/Jobs/JobGraph.inl | 14 +- Code/Framework/AzCore/Tests/JobGraphTests.cpp | 362 +++--------------- 7 files changed, 168 insertions(+), 386 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h index 1455f1311a..11d7f955b4 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -105,15 +106,16 @@ namespace AZ::Internal class alignas(alignof(max_align_t)) TypeErasedJob final { public: - // The inline buffer allows the TypeErasedJob to span two cache lines. Lambdas can capture 56 - // bytes of data (7 pointers/references on a 64-bit machine) before spilling to the heap. - constexpr static size_t BufferSize = 128 - sizeof(size_t) * 6 - sizeof(uint32_t) - sizeof(JobDescriptor); + // The inline buffer allows the TypeErasedJob to span two cache lines. Lambdas can capture 48 + // bytes of data (6 pointers/references on a 64-bit machine) before spilling to the heap. + constexpr static size_t BufferSize = + 128 - sizeof(size_t) * 6 - sizeof(uint32_t) - sizeof(JobDescriptor) - sizeof(AZStd::atomic); TypeErasedJob() = default; - template + template TypeErasedJob(JobDescriptor const& desc, Lambda&& lambda) noexcept - : m_descriptor{desc} + : m_descriptor{ desc } { JobTypeEraser eraser; m_invoker = eraser.ErasedInvoker(); @@ -147,9 +149,9 @@ namespace AZ::Internal // Indicates if this job is a root of the graph (with no dependencies) bool IsRoot(); - void AttachToJobGraph(CompiledJobGraph& graph) noexcept + void Init() noexcept { - m_graph = &graph; + m_dependencyCount = m_inboundLinkCount; } void Invoke() @@ -167,7 +169,7 @@ namespace AZ::Internal friend class JobWorker; // This relocation avoids branches needed if the lambda type is unknown - template + template void TypedRelocate(Lambda&& lambda, char* destination) { if constexpr (AZStd::is_trivially_move_constructible_v) @@ -195,6 +197,7 @@ namespace AZ::Internal // class to equal the alignment of the largest scalar type available on the system (generally // 16 bytes). char m_buffer[BufferSize]; + AZStd::atomic m_dependencyCount; // This value is an offset in a buffer that stores dependency tracking information. uint32_t m_successorOffset = 0; diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp index 16e4983752..aa7f696942 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp @@ -29,19 +29,18 @@ namespace AZ AZStd::vector&& jobs, AZStd::unordered_map>& links, size_t linkCount, - bool retained) - : m_remaining{ jobs.size() } - , m_retained{ retained } + JobGraph* parent) + : m_parent{ parent } { m_jobs = AZStd::move(jobs); - m_dependencyCounts = reinterpret_cast*>(azcalloc(sizeof(AZStd::atomic) * m_jobs.size())); m_successors.resize(linkCount); - uint32_t* cursor = m_successors.data(); + TypeErasedJob** cursor = m_successors.data(); for (size_t i = 0; i != m_jobs.size(); ++i) { TypeErasedJob& job = m_jobs[i]; + job.m_graph = this; job.m_successorOffset = cursor - m_successors.data(); cursor += job.m_outboundLinkCount; @@ -49,54 +48,42 @@ namespace AZ for (uint32_t j = 0; j != job.m_outboundLinkCount; ++j) { - m_successors[static_cast(job.m_successorOffset) + j] = links[i][j]; - } - - if (job.m_inboundLinkCount > 0) - { - m_dependencyCounts[i].store(job.m_inboundLinkCount, AZStd::memory_order_release); + m_successors[static_cast(job.m_successorOffset) + j] = &m_jobs[links[i][j]]; } } // TODO: Check for dependency cycles } - CompiledJobGraph::~CompiledJobGraph() + uint32_t CompiledJobGraph::Release() { - if (m_dependencyCounts) - { - azfree(m_dependencyCounts); - } - } + uint32_t remaining = --m_remaining; - void CompiledJobGraph::Release() - { - if (--m_remaining == 0) + if (m_parent) { - if (m_retained) + if (remaining == 1) { - m_remaining = m_jobs.size(); - for (size_t i = 0; i != m_jobs.size(); ++i) - { - TypeErasedJob& job = m_jobs[i]; - if (job.m_inboundLinkCount > 0) - { - m_dependencyCounts[i].store(job.m_inboundLinkCount, AZStd::memory_order_release); - } - } + // Allow the parent graph to be submitted again + m_parent->m_submitted = false; } - + } + else if (remaining == 0) + { if (m_waitEvent) { - m_waitEvent->m_submitted = false; m_waitEvent->Signal(); } - if (!m_retained) - { - azdestroy(this); - } + azdestroy(this); + return remaining; } + + if (m_waitEvent && remaining == (m_parent ? 1 : 0)) + { + m_waitEvent->Signal(); + } + + return remaining; } struct QueueStatus @@ -124,7 +111,7 @@ namespace AZ JobQueue(const JobQueue&) = delete; JobQueue& operator=(const JobQueue&) = delete; - bool Enqueue(TypeErasedJob* job); + void Enqueue(TypeErasedJob* job); TypeErasedJob* TryDequeue(); private: @@ -132,7 +119,7 @@ namespace AZ TypeErasedJob* m_queues[PriorityLevelCount][MaxQueueSize] = {}; }; - bool JobQueue::Enqueue(TypeErasedJob* job) + void JobQueue::Enqueue(TypeErasedJob* job) { uint8_t priority = job->GetPriorityNumber(); QueueStatus& status = m_status[priority]; @@ -159,7 +146,7 @@ namespace AZ expectedReserve = reserve; } - return status.head == status.tail - 1; + return; } // We failed to reserve a slot, try again @@ -233,9 +220,11 @@ namespace AZ void Enqueue(TypeErasedJob* job) { - if (m_queue.Enqueue(job)) + m_queue.Enqueue(job); + + if (!m_busy.exchange(true)) { - // The queue was empty prior to enqueueing the job, release the semaphore + // The worker was idle prior to enqueueing the job, release the semaphore m_semaphore.release(); } } @@ -245,14 +234,16 @@ namespace AZ { while (m_active) { + m_busy = false; m_semaphore.acquire(); - // m_semaphore.try_acquire_for(AZStd::chrono::microseconds{ 10 }); if (!m_active) { return; } + m_busy = true; + TypeErasedJob* job = m_queue.TryDequeue(); while (job) { @@ -260,10 +251,10 @@ namespace AZ // Decrement counts for all job successors for (size_t j = 0; j != job->m_outboundLinkCount; ++j) { - uint32_t successorIndex = job->m_graph->m_successors[job->m_successorOffset + j]; - if (--job->m_graph->m_dependencyCounts[successorIndex] == 0) + TypeErasedJob* successor = job->m_graph->m_successors[job->m_successorOffset + j]; + if (--successor->m_dependencyCount == 0) { - m_executor->Submit(job->m_graph->m_jobs[successorIndex]); + m_executor->Submit(*successor); } } @@ -277,6 +268,7 @@ namespace AZ AZStd::thread m_thread; AZStd::atomic m_active; + AZStd::atomic m_busy; AZStd::binary_semaphore m_semaphore; ::AZ::JobExecutor* m_executor; @@ -327,11 +319,6 @@ namespace AZ void JobExecutor::Submit(Internal::CompiledJobGraph& graph) { - for (Internal::TypeErasedJob& job : graph.Jobs()) - { - job.AttachToJobGraph(graph); - } - // Submit all jobs that have no inbound edges for (Internal::TypeErasedJob& job : graph.Jobs()) { diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h index 9418126678..60176f0717 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h @@ -18,6 +18,7 @@ namespace AZ { class JobGraphEvent; + class JobGraph; namespace Internal { @@ -30,9 +31,7 @@ namespace AZ AZStd::vector&& jobs, AZStd::unordered_map>& links, size_t linkCount, - bool retained); - - ~CompiledJobGraph(); + JobGraph* parent); AZStd::vector& Jobs() noexcept { @@ -40,19 +39,19 @@ namespace AZ } // Indicate that a constituent job has finished and decrement a counter to determine if the - // graph should be freed - void Release(); + // graph should be freed (returns the value after atomic decrement) + uint32_t Release(); private: friend class JobGraph; friend class JobWorker; AZStd::vector m_jobs; - AZStd::vector m_successors; - AZStd::atomic* m_dependencyCounts = nullptr; + AZStd::vector m_successors; JobGraphEvent* m_waitEvent = nullptr; + // The pointer to the parent graph is set only if it is retained + JobGraph* m_parent = nullptr; AZStd::atomic m_remaining; - bool m_retained; }; class JobWorker; diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp index b715e0ada7..6b34f1273a 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp @@ -30,10 +30,27 @@ namespace AZ { if (m_retained && m_compiledJobGraph) { - azdestroy(m_compiledJobGraph); + // This job graph has already finished and we are potentially responsible for its destruction + if (m_compiledJobGraph->Release() == 0) + { + azdestroy(m_compiledJobGraph); + } } } + void JobGraph::Reset() + { + AZ_Assert(!m_submitted, "Cannot reset a job graph while it is in flight"); + if (m_compiledJobGraph) + { + azdestroy(m_compiledJobGraph); + m_compiledJobGraph = nullptr; + } + m_jobs.clear(); + m_links.clear(); + m_linkCount = 0; + } + void JobGraph::Submit(JobGraphEvent* waitEvent) { SubmitOnExecutor(JobExecutor::Instance(), waitEvent); @@ -41,20 +58,28 @@ namespace AZ void JobGraph::SubmitOnExecutor(JobExecutor& executor, JobGraphEvent* waitEvent) { - m_submitted = true; - if (!m_compiledJobGraph) { - m_compiledJobGraph = aznew CompiledJobGraph(AZStd::move(m_jobs), m_links, m_linkCount, m_retained); + m_compiledJobGraph = aznew CompiledJobGraph(AZStd::move(m_jobs), m_links, m_linkCount, m_retained ? this : nullptr); } m_compiledJobGraph->m_waitEvent = waitEvent; + m_compiledJobGraph->m_remaining = m_compiledJobGraph->m_jobs.size() + (m_retained ? 1 : 0); + for (size_t i = 0; i != m_compiledJobGraph->m_jobs.size(); ++i) + { + m_compiledJobGraph->m_jobs[i].Init(); + } executor.Submit(*m_compiledJobGraph); - if (waitEvent) + if (m_retained) { - waitEvent->m_submitted = true; + m_submitted = true; + } + else + { + m_compiledJobGraph = nullptr; + Reset(); } } } diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h index 62565ea78c..070236b0b5 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h @@ -12,7 +12,7 @@ // suited in the private CompiledJobGraph implementation instead to keep this header lean. #include #include -#include +#include #include #include #include @@ -30,10 +30,14 @@ namespace AZ class JobToken final { public: - // Indicate that this job must finish before the job passed as the argument + // Indicate that this job must finish before the job token(s) passed as the argument template void Precedes(JT&... tokens); + // Indicate that this job must finish after the job token(s) passed as the argument + template + void Succeeds(JT&... tokens); + private: friend class JobGraph; @@ -67,7 +71,6 @@ namespace AZ void Signal(); AZStd::binary_semaphore m_semaphore; - bool m_submitted = false; }; // The JobGraph encapsulates a set of jobs and their interdependencies. After adding @@ -81,13 +84,18 @@ namespace AZ public: ~JobGraph(); + // Reset the state of the job graph to begin recording jobs and edges again + // NOTE: Graph must be in a "settled" state (cannot be in-flight) + void Reset(); + // Add a job to the graph, retrieiving a token that can be used to express dependencies // between jobs. The first argument specifies the JobKind, used for tracking the job. + // NOTE: This operation is invalid if the graph is in-flight template JobToken AddJob(JobDescriptor const& descriptor, Lambda&& lambda); template - AZStd::fixed_vector AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas); + AZStd::array AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas); // By default, you are responsible for retaining the JobGraph, indicating you promise that // this JobGraph will live as long as it takes for all constituent jobs to complete. @@ -103,6 +111,7 @@ namespace AZ // of the job graph is expected to rely on either indirection, or safe overwriting // of previously used memory to supply new data (this can even be done as the first // job in the graph). + // NOTE: This operation is invalid if the graph is in-flight void Detach(); // Invoke the job graph, asserting if there are dependency violations. Note that @@ -122,6 +131,7 @@ namespace AZ private: friend class JobToken; + friend class Internal::CompiledJobGraph; Internal::CompiledJobGraph* m_compiledJobGraph = nullptr; @@ -132,7 +142,7 @@ namespace AZ uint32_t m_linkCount = 0; bool m_retained = true; - bool m_submitted = false; + AZStd::atomic m_submitted = false; }; } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl index f541d9923f..ad1fb3505c 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl @@ -22,15 +22,19 @@ namespace AZ (PrecedesInternal(tokens), ...); } + template + inline void JobToken::Succeeds(JT&... tokens) + { + (tokens.PrecedesInternal(*this), ...); + } + inline bool JobGraphEvent::IsSignaled() { - AZ_Assert(m_submitted, "Querying the status of a job graph event that was never submitted along with the jobgraph"); return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 }); } inline void JobGraphEvent::Wait() { - AZ_Assert(m_submitted, "Waiting on a job graph event that was never submitted along with the jobgraph"); m_semaphore.acquire(); } @@ -42,7 +46,7 @@ namespace AZ template inline JobToken JobGraph::AddJob(JobDescriptor const& desc, Lambda&& lambda) { - AZ_Assert(!m_submitted, "Cannot mutate a JobGraph that was previously submitted."); + AZ_Assert(!m_submitted, "Cannot mutate a JobGraph that was previously submitted or in flight."); m_jobs.emplace_back(desc, AZStd::forward(lambda)); @@ -50,9 +54,9 @@ namespace AZ } template - inline AZStd::fixed_vector AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas) + inline AZStd::array JobGraph::AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas) { - return { AddJob(descriptor, lambdas)... }; + return { AddJob(descriptor, AZStd::forward(lambdas))... }; } inline void JobGraph::Detach() diff --git a/Code/Framework/AzCore/Tests/JobGraphTests.cpp b/Code/Framework/AzCore/Tests/JobGraphTests.cpp index 175881b89a..b080e5b679 100644 --- a/Code/Framework/AzCore/Tests/JobGraphTests.cpp +++ b/Code/Framework/AzCore/Tests/JobGraphTests.cpp @@ -336,8 +336,7 @@ namespace UnitTest // d a.Precedes(b, c); - b.Precedes(d); - c.Precedes(d); + d.Succeeds(b, c); JobGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); @@ -487,8 +486,7 @@ namespace UnitTest a.Precedes(b, c); b.Precedes(d); c.Precedes(e, f); - e.Precedes(g); - f.Precedes(g); + g.Succeeds(e, f); g.Precedes(d); JobGraphEvent ev; @@ -511,338 +509,94 @@ namespace Benchmark class JobGraphBenchmarkFixture : public ::benchmark::Fixture { public: - static const int32_t LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1; - static const int32_t MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1024; - static const int32_t HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH = 1048576; - - static const int32_t SMALL_NUMBER_OF_JOBS = 10; - static const int32_t MEDIUM_NUMBER_OF_JOBS = 1024; - static const int32_t LARGE_NUMBER_OF_JOBS = 16384; - static AZStd::atomic s_numIncompleteJobs; - - int m_depth = 1; - JobGraph* graphs; - void SetUp(benchmark::State&) override { - s_numIncompleteJobs = 0; - - m_executor = aznew JobExecutor(0); - graphs = new JobGraph[4]; - - // Generate some random priorities - m_randomPriorities.resize(LARGE_NUMBER_OF_JOBS); - std::mt19937_64 randomPriorityGenerator(1); // Always use the same seed - std::uniform_int_distribution<> randomPriorityDistribution(0, static_cast(AZ::JobPriority::PRIORITY_COUNT)); - std::generate( - m_randomPriorities.begin(), m_randomPriorities.end(), - [&randomPriorityDistribution, &randomPriorityGenerator]() - { - return randomPriorityDistribution(randomPriorityGenerator); - }); - - // Generate some random depths - m_randomDepths.resize(LARGE_NUMBER_OF_JOBS); - std::mt19937_64 randomDepthGenerator(1); // Always use the same seed - std::uniform_int_distribution<> randomDepthDistribution( - LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - std::generate( - m_randomDepths.begin(), m_randomDepths.end(), - [&randomDepthDistribution, &randomDepthGenerator]() - { - return randomDepthDistribution(randomDepthGenerator); - }); - - for (size_t i = 0; i != 4; ++i) - { - graphs[i].AddJob( - descriptors[i], - [this] - { - benchmark::DoNotOptimize(CalculatePi(m_depth)); - --s_numIncompleteJobs; - }); - } + executor = new JobExecutor; + graph = new JobGraph; } void TearDown(benchmark::State&) override { - delete[] graphs; - azdestroy(m_executor); - m_randomDepths = {}; - m_randomPriorities = {}; + delete graph; + delete executor; } JobDescriptor descriptors[4] = { { "critical", "benchmark", JobPriority::CRITICAL }, { "high", "benchmark", JobPriority::HIGH }, - { "mediium", "benchmark", JobPriority::MEDIUM }, + { "medium", "benchmark", JobPriority::MEDIUM }, { "low", "benchmark", JobPriority::LOW } }; - static inline double CalculatePi(AZ::u32 depth) - { - double pi = 0.0; - for (AZ::u32 i = 0; i < depth; ++i) - { - const double numerator = static_cast(((i % 2) * 2) - 1); - const double denominator = static_cast((2 * i) - 1); - pi += numerator / denominator; - } - return (pi - 1.0) * 4; - } - - void RunCalculatePiJob(int32_t depth, int8_t priority) - { - m_depth = depth; - ++s_numIncompleteJobs; - - graphs[priority].SubmitOnExecutor(*m_executor); - } - - void RunMultipleCalculatePiJobsWithDefaultPriority(uint32_t numberOfJobs, int32_t depth) - { - for (size_t i = 0; i != numberOfJobs; ++i) - { - RunCalculatePiJob(depth, 2); - } - - while (s_numIncompleteJobs > 0) - { - } - } - - void RunMultipleCalculatePiJobsWithRandomPriority(uint32_t numberOfJobs, int32_t depth) - { - for (size_t i = 0; i != numberOfJobs; ++i) - { - RunCalculatePiJob(depth, m_randomPriorities[i]); - } - - while (s_numIncompleteJobs > 0) - { - } - } - - void RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(uint32_t numberOfJobs) - { - for (size_t i = 0; i != numberOfJobs; ++i) - { - RunCalculatePiJob(m_randomDepths[i], 0); - } - - while (s_numIncompleteJobs > 0) - { - } - } - - void RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(uint32_t numberOfJobs) - { - for (size_t i = 0; i != numberOfJobs; ++i) - { - RunCalculatePiJob(m_randomDepths[i], m_randomPriorities[i]); - } - - while (s_numIncompleteJobs > 0) - { - } - } - - JobExecutor* m_executor; - AZStd::vector m_randomDepths; - AZStd::vector m_randomPriorities; + JobGraph* graph; + JobExecutor* executor; }; - AZStd::atomic JobGraphBenchmarkFixture::s_numIncompleteJobs = 0; - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + BENCHMARK_F(JobGraphBenchmarkFixture, QueueToDequeue)(benchmark::State& state) { + graph->AddJob( + descriptors[2], + [] + { + }); for (auto _ : state) { - RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + JobGraphEvent ev; + graph->SubmitOnExecutor(*executor, &ev); + ev.Wait(); } } - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + BENCHMARK_F(JobGraphBenchmarkFixture, OneAfterAnother)(benchmark::State& state) { + auto a = graph->AddJob( + descriptors[2], + [] + { + }); + auto b = graph->AddJob( + descriptors[2], + [] + { + }); + a.Precedes(b); + for (auto _ : state) { - RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); + JobGraphEvent ev; + graph->SubmitOnExecutor(*executor, &ev); + ev.Wait(); } + executor->Drain(); } - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfLightWeightJobsWithDefaultPriority)(benchmark::State& state) + BENCHMARK_F(JobGraphBenchmarkFixture, FourToOneJoin)(benchmark::State& state) { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } + auto [a, b, c, d, e] = graph->AddJobs( + descriptors[2], + [] + { + }, + [] + { + }, + [] + { + }, + [] + { + }, + [] + { + }); - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } + e.Succeeds(a, b, c, d); - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) - { for (auto _ : state) { - RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfMediumWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(SMALL_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(MEDIUM_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfHeavyWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithDefaultPriority(LARGE_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(SMALL_NUMBER_OF_JOBS); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(MEDIUM_NUMBER_OF_JOBS); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfRandomWeightJobsWithDefaultPriority)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndDefaultPriority(LARGE_NUMBER_OF_JOBS); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfLightWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, LIGHT_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfMediumWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, MEDIUM_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(SMALL_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(MEDIUM_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfHeavyWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomPriority(LARGE_NUMBER_OF_JOBS, HEAVY_WEIGHT_JOB_CALCULATE_PI_DEPTH); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunSmallNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(SMALL_NUMBER_OF_JOBS); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunMediumNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(MEDIUM_NUMBER_OF_JOBS); - } - } - - BENCHMARK_F(JobGraphBenchmarkFixture, RunLargeNumberOfRandomWeightJobsWithRandomPriorities)(benchmark::State& state) - { - for (auto _ : state) - { - RunMultipleCalculatePiJobsWithRandomDepthAndRandomPriority(LARGE_NUMBER_OF_JOBS); + JobGraphEvent ev; + graph->SubmitOnExecutor(*executor, &ev); + ev.Wait(); } + executor->Drain(); } } // namespace Benchmark #endif From 6ac74ad41e20a0ec31b372a039ff080338b475d4 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 4 Aug 2021 03:12:17 -0600 Subject: [PATCH 07/18] Resolve clang compiler error "If constexpr" branches are evaluated at template instantiation time, but static assertions receiving false are triggered even earlier. Signed-off-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h index 11d7f955b4..e57ba85176 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h +++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h @@ -59,7 +59,7 @@ namespace AZ::Internal else { static_assert( - false, + AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " "constructible."); } @@ -187,7 +187,7 @@ namespace AZ::Internal else { static_assert( - false, + AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " "constructible."); } From 4d058f329b0eb742adc81040a12c9cae85357c3a Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 4 Aug 2021 03:23:16 -0600 Subject: [PATCH 08/18] Use exponential backoff during job submission when ring buffers are full Signed-off-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp | 9 +++++---- Code/Framework/AzCore/Tests/JobGraphTests.cpp | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp index aa7f696942..83823515c1 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp @@ -9,13 +9,14 @@ #include #include -#include #include #include -#include +#include #include #include +#include #include +#include #include @@ -124,6 +125,7 @@ namespace AZ uint8_t priority = job->GetPriorityNumber(); QueueStatus& status = m_status[priority]; + AZStd::exponential_backoff backoff; while (true) { uint16_t reserve = status.reserve.load(); @@ -153,8 +155,7 @@ namespace AZ } else { - // TODO need exponential backup here - AZStd::this_thread::sleep_for(AZStd::chrono::microseconds{ 100 }); + backoff.wait(); } } } diff --git a/Code/Framework/AzCore/Tests/JobGraphTests.cpp b/Code/Framework/AzCore/Tests/JobGraphTests.cpp index b080e5b679..469773f471 100644 --- a/Code/Framework/AzCore/Tests/JobGraphTests.cpp +++ b/Code/Framework/AzCore/Tests/JobGraphTests.cpp @@ -565,7 +565,6 @@ namespace Benchmark graph->SubmitOnExecutor(*executor, &ev); ev.Wait(); } - executor->Drain(); } BENCHMARK_F(JobGraphBenchmarkFixture, FourToOneJoin)(benchmark::State& state) @@ -596,7 +595,6 @@ namespace Benchmark graph->SubmitOnExecutor(*executor, &ev); ev.Wait(); } - executor->Drain(); } } // namespace Benchmark #endif From d2f2a186cb124a34ed9811f6ae1baa3243241b0c Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 4 Aug 2021 03:32:49 -0600 Subject: [PATCH 09/18] Add forward declaration needed on clang Signed-off-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h | 2 +- Code/Framework/AzCore/AzCore/Jobs/JobGraph.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h index 60176f0717..746edf00a1 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h +++ b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h @@ -43,7 +43,7 @@ namespace AZ uint32_t Release(); private: - friend class JobGraph; + friend class ::AZ::JobGraph; friend class JobWorker; AZStd::vector m_jobs; diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h index 070236b0b5..872a9a4e5c 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h +++ b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h @@ -24,6 +24,7 @@ namespace AZ class CompiledJobGraph; } class JobExecutor; + class JobGraph; // A JobToken is returned each time a Job is added to the JobGraph. JobTokens are used to // express dependencies between jobs within the graph. From eaa6e087cf7602e4fc57a087d13e80b24ba7941b Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Thu, 5 Aug 2021 14:37:59 -0600 Subject: [PATCH 10/18] JobGraph -> TaskGraph (and associated classes/files) This commit also addresses all PR feedback Signed-off-by: Jeremy Ong --- .../AzCore/Jobs/Internal/JobTypeEraser.cpp | 76 ---- .../AzCore/Jobs/Internal/JobTypeEraser.h | 232 ---------- .../AzCore/AzCore/Jobs/JobDescriptor.h | 49 --- .../AzCore/AzCore/Jobs/JobExecutor.h | 85 ---- .../Framework/AzCore/AzCore/Jobs/JobGraph.cpp | 85 ---- Code/Framework/AzCore/AzCore/Jobs/JobGraph.h | 150 ------- .../AzCore/AzCore/Task/Internal/Task.cpp | 58 +++ .../AzCore/AzCore/Task/Internal/Task.h | 180 ++++++++ .../AzCore/AzCore/Task/Internal/Task.inl | 84 ++++ .../AzCore/AzCore/Task/Internal/TaskConfig.h | 14 + .../AzCore/AzCore/Task/TaskDescriptor.h | 49 +++ .../JobExecutor.cpp => Task/TaskExecutor.cpp} | 176 ++++---- .../AzCore/AzCore/Task/TaskExecutor.h | 94 ++++ .../AzCore/AzCore/Task/TaskGraph.cpp | 85 ++++ Code/Framework/AzCore/AzCore/Task/TaskGraph.h | 151 +++++++ .../{Jobs/JobGraph.inl => Task/TaskGraph.inl} | 26 +- .../AzCore/AzCore/azcore_files.cmake | 18 +- .../{JobGraphTests.cpp => TaskTests.cpp} | 405 ++++++++++++------ .../AzCore/Tests/azcoretests_files.cmake | 2 +- 19 files changed, 1109 insertions(+), 910 deletions(-) delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp delete mode 100644 Code/Framework/AzCore/AzCore/Jobs/JobGraph.h create mode 100644 Code/Framework/AzCore/AzCore/Task/Internal/Task.cpp create mode 100644 Code/Framework/AzCore/AzCore/Task/Internal/Task.h create mode 100644 Code/Framework/AzCore/AzCore/Task/Internal/Task.inl create mode 100644 Code/Framework/AzCore/AzCore/Task/Internal/TaskConfig.h create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskDescriptor.h rename Code/Framework/AzCore/AzCore/{Jobs/JobExecutor.cpp => Task/TaskExecutor.cpp} (62%) create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskExecutor.h create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp create mode 100644 Code/Framework/AzCore/AzCore/Task/TaskGraph.h rename Code/Framework/AzCore/AzCore/{Jobs/JobGraph.inl => Task/TaskGraph.inl} (50%) rename Code/Framework/AzCore/Tests/{JobGraphTests.cpp => TaskTests.cpp} (53%) diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp deleted file mode 100644 index 043f232e32..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 - -namespace AZ::Internal -{ - TypeErasedJob::TypeErasedJob(TypeErasedJob&& other) noexcept - { - if (!other.m_relocator || other.m_lambda != other.m_buffer) - { - // The type-erased lambda is trivially relocatable OR, the lambda is heap allocated - memcpy(this, &other, sizeof(TypeErasedJob)); - - if (other.m_lambda == other.m_buffer) - { - m_lambda = m_buffer; - } - - // Prevent deletion in the event the lambda had spilled to the heap - other.m_lambda = nullptr; - return; - } - - // At this point, we know the lambda was inlined - m_lambda = m_buffer; - - m_invoker = other.m_invoker; - m_relocator = other.m_relocator; - m_destroyer = other.m_destroyer; - - // We now own the lambda, so clear the moved-from job's destroyer - other.m_destroyer = nullptr; - other.m_invoker = nullptr; - - m_relocator(m_buffer, other.m_buffer); - } - - TypeErasedJob& TypeErasedJob::operator=(TypeErasedJob&& other) noexcept - { - if (this == &other) - { - return *this; - } - - this->~TypeErasedJob(); - - new (this) TypeErasedJob{ AZStd::move(other) }; - - return *this; - } - - TypeErasedJob::~TypeErasedJob() - { - if (m_lambda) - { - if (m_destroyer) - { - // The presence of m_destroyer indicates that the lambda is not trivially destructible - m_destroyer(m_lambda); - } - - if (m_lambda != m_buffer) - { - // We've spilled the lambda into the heap, free its memory - azfree(m_lambda); - } - } - } - -} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h deleted file mode 100644 index e57ba85176..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobTypeEraser.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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 -#include -#include - -namespace AZ::Internal -{ - using JobInvoke_t = void (*)(void* lambda); - using JobRelocate_t = void (*)(void* dst, void* src); - using JobDestroy_t = void (*)(void* obj); - - class CompiledJobGraph; - - // Lambdas are opaque types and we cannot extract any member function pointers. In order to store lambdas in a - // type erased fashion, we instead use a single function call indirection, invoking the lambda function in a - // static class function which has a stable address in memory. The Erased* methods return addresses to the - // indirect callers of the lambda copy/move assignment operators, call operator, and destructor. - // - // For lambdas that are trivially relocatable, both the returned move and copy assignment function pointers - // will be nullptr. - // - // Lambdas that are trivially destructible will result in a nullptr returned JobDestroy_t pointer. - // - // The class will check that the lambda is copy assignable or movable. - template - class JobTypeEraser final - { - public: - constexpr JobInvoke_t ErasedInvoker() - { - return reinterpret_cast(Invoker); - } - - constexpr JobRelocate_t ErasedRelocator() - { - if constexpr (AZStd::is_trivially_move_constructible_v) - { - return nullptr; - } - else if constexpr (AZStd::is_move_constructible_v) - { - return reinterpret_cast(Mover); - } - else if constexpr (AZStd::is_copy_constructible_v) - { - return reinterpret_cast(Copyer); - } - else - { - static_assert( - AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, - "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " - "constructible."); - } - } - - constexpr JobDestroy_t ErasedDestroyer() - { - if constexpr (AZStd::is_trivially_destructible_v) - { - return nullptr; - } - else - { - return reinterpret_cast(Destroyer); - } - } - - private: - constexpr static void Invoker(Lambda* lambda) - { - lambda->operator()(); - } - - constexpr static void Mover(Lambda* dst, Lambda* src) - { - new (dst) Lambda{ AZStd::move(*src) }; - } - - constexpr static void Copyer(Lambda* dst, Lambda* src) - { - new (dst) Lambda{ *src }; - } - - constexpr static void Destroyer(Lambda* lambda) - { - lambda->~Lambda(); - } - }; - - // The TypeErasedJob encapsulates member function pointers to store in a homogeneously-typed container - // The function signature of all lambdas encoded in a TypeErasedJob is void(*)(). The lambdas can capture - // data, in which case the data is inlined in this structure if the payload is less than or equal to the - // buffer size. Otherwise, the data is heap allocated. - class alignas(alignof(max_align_t)) TypeErasedJob final - { - public: - // The inline buffer allows the TypeErasedJob to span two cache lines. Lambdas can capture 48 - // bytes of data (6 pointers/references on a 64-bit machine) before spilling to the heap. - constexpr static size_t BufferSize = - 128 - sizeof(size_t) * 6 - sizeof(uint32_t) - sizeof(JobDescriptor) - sizeof(AZStd::atomic); - - TypeErasedJob() = default; - - template - TypeErasedJob(JobDescriptor const& desc, Lambda&& lambda) noexcept - : m_descriptor{ desc } - { - JobTypeEraser eraser; - m_invoker = eraser.ErasedInvoker(); - m_relocator = eraser.ErasedRelocator(); - m_destroyer = eraser.ErasedDestroyer(); - - // NOTE: This code is conservative in that extended alignment requirements result in a heap - // spill, even if the lambda could have occupied a portion of the inline buffer with a base - // pointer adjustment. - if constexpr (sizeof(Lambda) <= BufferSize && alignof(Lambda) <= alignof(max_align_t)) - { - TypedRelocate(AZStd::forward(lambda), m_buffer); - m_lambda = m_buffer; - } - else - { - // Lambda has spilled to the heap (or requires extended alignment) - m_lambda = reinterpret_cast(azmalloc(sizeof(Lambda), alignof(Lambda))); - TypedRelocate(AZStd::forward(lambda), m_lambda); - } - } - - TypeErasedJob(TypeErasedJob&& other) noexcept; - - TypeErasedJob& operator=(TypeErasedJob&& other) noexcept; - - ~TypeErasedJob(); - - void Link(TypeErasedJob& other); - - // Indicates if this job is a root of the graph (with no dependencies) - bool IsRoot(); - - void Init() noexcept - { - m_dependencyCount = m_inboundLinkCount; - } - - void Invoke() - { - m_invoker(m_lambda); - } - - uint8_t GetPriorityNumber() const - { - return static_cast(m_descriptor.priority); - } - - private: - friend class CompiledJobGraph; - friend class JobWorker; - - // This relocation avoids branches needed if the lambda type is unknown - template - void TypedRelocate(Lambda&& lambda, char* destination) - { - if constexpr (AZStd::is_trivially_move_constructible_v) - { - memcpy(destination, reinterpret_cast(&lambda), sizeof(Lambda)); - } - else if constexpr (AZStd::is_move_constructible_v) - { - new (destination) Lambda{ AZStd::move(lambda) }; - } - else if constexpr (AZStd::is_copy_constructible_v) - { - new (destination) Lambda{ lambda }; - } - else - { - static_assert( - AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, - "Job lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " - "constructible."); - } - } - - // Small buffer optimization for lambdas. We cover our bases here by enforcing alignment on the - // class to equal the alignment of the largest scalar type available on the system (generally - // 16 bytes). - char m_buffer[BufferSize]; - AZStd::atomic m_dependencyCount; - - // This value is an offset in a buffer that stores dependency tracking information. - uint32_t m_successorOffset = 0; - uint32_t m_inboundLinkCount = 0; - uint32_t m_outboundLinkCount = 0; - - // May point to the inlined payload buffer, or heap - char* m_lambda = nullptr; - - CompiledJobGraph* m_graph = nullptr; - - JobInvoke_t m_invoker; - - // If nullptr, the lambda is trivially relocatable (via memcpy). Otherwise, it must be invoked - // when instances of this class are moved. - JobRelocate_t m_relocator; - JobDestroy_t m_destroyer; - - JobDescriptor m_descriptor; - }; - - inline void TypeErasedJob::Link(TypeErasedJob& other) - { - ++m_outboundLinkCount; - ++other.m_inboundLinkCount; - } - - inline bool TypeErasedJob::IsRoot() - { - return m_inboundLinkCount == 0; - } -} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h b/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h deleted file mode 100644 index 82a9603bd5..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/JobDescriptor.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 - -namespace AZ -{ - // Job priorities MAY be used judiciously to fine tune runtime execution, with the understanding - // that profiling is needed to understand what the critical path per frame is. Modifying - // job priorities is an EXPERT setting that should succeed a healthy dose of measurement. - enum class JobPriority : uint8_t - { - CRITICAL = 0, - HIGH = 1, - MEDIUM = 2, // Default - LOW = 3, - PRIORITY_COUNT = 4, - }; - - // All submitted jobs are associated with a JobDescriptor which defines the priority, affinitization, - // and tracking of the job resource utilization. - // - // TODO: Define various job kinds and provide a mechanism for cpuMask computation on different systems. - struct JobDescriptor - { - // Unique job kind label (e.g. "frustum culling") - // Job names *must* be provided - const char* jobName = nullptr; - - // Associates a set of job kinds together for budget tracking (e.g. "graphics") - const char* jobGroup = nullptr; - - // EXPERTS ONLY. Jobs of higher priority are executed ahead of any lower priority jobs - // that were queued before it provided they had not yet started - JobPriority priority = JobPriority::MEDIUM; - - // EXPERTS ONLY. A bitmask that restricts jobs of this kind to run only on cores - // corresponding to a set bit. 0 is synonymous with all bits set - uint32_t cpuMask = 0; - }; -} diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h b/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h deleted file mode 100644 index 746edf00a1..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 -#include -#include - -namespace AZ -{ - class JobGraphEvent; - class JobGraph; - - namespace Internal - { - class CompiledJobGraph final - { - public: - AZ_CLASS_ALLOCATOR(CompiledJobGraph, SystemAllocator, 0) - - CompiledJobGraph( - AZStd::vector&& jobs, - AZStd::unordered_map>& links, - size_t linkCount, - JobGraph* parent); - - AZStd::vector& Jobs() noexcept - { - return m_jobs; - } - - // Indicate that a constituent job has finished and decrement a counter to determine if the - // graph should be freed (returns the value after atomic decrement) - uint32_t Release(); - - private: - friend class ::AZ::JobGraph; - friend class JobWorker; - - AZStd::vector m_jobs; - AZStd::vector m_successors; - JobGraphEvent* m_waitEvent = nullptr; - // The pointer to the parent graph is set only if it is retained - JobGraph* m_parent = nullptr; - AZStd::atomic m_remaining; - }; - - class JobWorker; - } // namespace Internal - - class JobExecutor - { - public: - AZ_CLASS_ALLOCATOR(JobExecutor, SystemAllocator, 0); - - static JobExecutor& Instance(); - - // Passing 0 for the threadCount requests for the thread count to match the hardware concurrency - JobExecutor(uint32_t threadCount = 0); - ~JobExecutor(); - - void Submit(Internal::CompiledJobGraph& graph); - - void Submit(Internal::TypeErasedJob& job); - - // Busy wait until jobs are cleared from the executor (note, does not prevent future jobs from being submitted) - void Drain(); - private: - friend class Internal::JobWorker; - - Internal::JobWorker* m_workers; - uint32_t m_threadCount = 0; - AZStd::atomic m_lastSubmission; - AZStd::atomic m_remaining; - }; -} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp deleted file mode 100644 index 6b34f1273a..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 - -namespace AZ -{ - using Internal::CompiledJobGraph; - - void JobToken::PrecedesInternal(JobToken& comesAfter) - { - AZ_Assert(!m_parent.m_submitted, "Cannot mutate a JobGraph that was previously submitted."); - - // Increment inbound/outbound edge counts - m_parent.m_jobs[m_index].Link(m_parent.m_jobs[comesAfter.m_index]); - - m_parent.m_links[m_index].emplace_back(comesAfter.m_index); - - ++m_parent.m_linkCount; - } - - JobGraph::~JobGraph() - { - if (m_retained && m_compiledJobGraph) - { - // This job graph has already finished and we are potentially responsible for its destruction - if (m_compiledJobGraph->Release() == 0) - { - azdestroy(m_compiledJobGraph); - } - } - } - - void JobGraph::Reset() - { - AZ_Assert(!m_submitted, "Cannot reset a job graph while it is in flight"); - if (m_compiledJobGraph) - { - azdestroy(m_compiledJobGraph); - m_compiledJobGraph = nullptr; - } - m_jobs.clear(); - m_links.clear(); - m_linkCount = 0; - } - - void JobGraph::Submit(JobGraphEvent* waitEvent) - { - SubmitOnExecutor(JobExecutor::Instance(), waitEvent); - } - - void JobGraph::SubmitOnExecutor(JobExecutor& executor, JobGraphEvent* waitEvent) - { - if (!m_compiledJobGraph) - { - m_compiledJobGraph = aznew CompiledJobGraph(AZStd::move(m_jobs), m_links, m_linkCount, m_retained ? this : nullptr); - } - - m_compiledJobGraph->m_waitEvent = waitEvent; - m_compiledJobGraph->m_remaining = m_compiledJobGraph->m_jobs.size() + (m_retained ? 1 : 0); - for (size_t i = 0; i != m_compiledJobGraph->m_jobs.size(); ++i) - { - m_compiledJobGraph->m_jobs[i].Init(); - } - - executor.Submit(*m_compiledJobGraph); - - if (m_retained) - { - m_submitted = true; - } - else - { - m_compiledJobGraph = nullptr; - Reset(); - } - } -} diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h b/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h deleted file mode 100644 index 872a9a4e5c..0000000000 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 - -// NOTE: If adding additional header/symbol dependencies, consider if such additions are better -// suited in the private CompiledJobGraph implementation instead to keep this header lean. -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace Internal - { - class CompiledJobGraph; - } - class JobExecutor; - class JobGraph; - - // A JobToken is returned each time a Job is added to the JobGraph. JobTokens are used to - // express dependencies between jobs within the graph. - class JobToken final - { - public: - // Indicate that this job must finish before the job token(s) passed as the argument - template - void Precedes(JT&... tokens); - - // Indicate that this job must finish after the job token(s) passed as the argument - template - void Succeeds(JT&... tokens); - - private: - friend class JobGraph; - - void PrecedesInternal(JobToken& comesAfter); - - // Only the JobGraph should be creating JobToken - JobToken(JobGraph& parent, size_t index); - - JobGraph& m_parent; - size_t m_index; - }; - - // A JobGraphEvent may be used to block until a job graph has finished executing. Usage - // is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting - // the graph without synchronization over the course of the frame). However, the event - // is useful for the edges of the computation graph. - // - // You are responsible for ensuring the event object lifetime exceeds the job graph lifetime. - // - // After the JobGraphEvent is signaled, you are allowed to reuse the same JobGraphEvent - // for a future submission. - class JobGraphEvent - { - public: - bool IsSignaled(); - void Wait(); - - private: - friend class ::AZ::Internal::CompiledJobGraph; - friend class JobGraph; - void Signal(); - - AZStd::binary_semaphore m_semaphore; - }; - - // The JobGraph encapsulates a set of jobs and their interdependencies. After adding - // jobs, and marking dependencies as necessary, the entire graph is submitted via - // the JobGraph::Submit method. - // - // The JobGraph MAY be retained across multiple frames and resubmitted, provided the - // user provides some guarantees (see comments associated with JobGraph::Retain). - class JobGraph final - { - public: - ~JobGraph(); - - // Reset the state of the job graph to begin recording jobs and edges again - // NOTE: Graph must be in a "settled" state (cannot be in-flight) - void Reset(); - - // Add a job to the graph, retrieiving a token that can be used to express dependencies - // between jobs. The first argument specifies the JobKind, used for tracking the job. - // NOTE: This operation is invalid if the graph is in-flight - template - JobToken AddJob(JobDescriptor const& descriptor, Lambda&& lambda); - - template - AZStd::array AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas); - - // By default, you are responsible for retaining the JobGraph, indicating you promise that - // this JobGraph will live as long as it takes for all constituent jobs to complete. - // Once retained, this job graph can be resubmitted after completion without any - // modifications. JobTokens that were created as a result of adding jobs used to - // mark dependencies DO NOT need to outlive the job graph. - // - // Invoking Detach PRIOR to submission indicates you wish the jobs associated with this - // JobGraph to deallocate upon completion. After invoking Detach, you may let this JobGraph - // go out of scope or deallocate after submission. - // - // NOTE: The JobGraph has no concept of resources used by design. Resubmission - // of the job graph is expected to rely on either indirection, or safe overwriting - // of previously used memory to supply new data (this can even be done as the first - // job in the graph). - // NOTE: This operation is invalid if the graph is in-flight - void Detach(); - - // Invoke the job graph, asserting if there are dependency violations. Note that - // submitting the same graph multiple times to process simultaneously is VALID - // behavior. This is, for example, a mechanism that allows a job graph to loop - // in perpetuity (in fact, the entire frame could be modeled as a single job graph, - // where the final job resubmits the job graph again). - // - // This API is not designed to protect against memory safety violations (nothing - // can prevent a user from incorrectly aliasing memory unsafely even without repeated - // submission). To catch memory safety violations, it is ENCOURAGED that you access - // data through JobResource handles. - void Submit(JobGraphEvent* waitEvent = nullptr); - - // Same as submit but run on a different executor than the default system executor - void SubmitOnExecutor(JobExecutor& executor, JobGraphEvent* waitEvent = nullptr); - - private: - friend class JobToken; - friend class Internal::CompiledJobGraph; - - Internal::CompiledJobGraph* m_compiledJobGraph = nullptr; - - AZStd::vector m_jobs; - - // Job index |-> Dependent job indices - AZStd::unordered_map> m_links; - - uint32_t m_linkCount = 0; - bool m_retained = true; - AZStd::atomic m_submitted = false; - }; -} // namespace AZ - -#include diff --git a/Code/Framework/AzCore/AzCore/Task/Internal/Task.cpp b/Code/Framework/AzCore/AzCore/Task/Internal/Task.cpp new file mode 100644 index 0000000000..b0e5da8fc0 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/Internal/Task.cpp @@ -0,0 +1,58 @@ +/* + * 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 + +namespace AZ::Internal +{ + Task::Task(Task&& other) noexcept + { + if (!other.m_relocator) + { + // The type-erased lambda is trivially relocatable OR, the lambda is heap allocated + memcpy(this, &other, sizeof(Task)); + + // Prevent deletion in the event the lambda had spilled to the heap + other.m_destroyer = nullptr; + return; + } + + m_invoker = other.m_invoker; + m_relocator = other.m_relocator; + m_destroyer = other.m_destroyer; + + // We now own the lambda, so clear the moved-from task's destroyer + other.m_destroyer = nullptr; + + m_relocator(m_lambda, other.m_lambda); + } + + Task& Task::operator=(Task&& other) noexcept + { + if (this == &other) + { + return *this; + } + + this->~Task(); + + new (this) Task{ AZStd::move(other) }; + + return *this; + } + + Task::~Task() + { + if (m_destroyer) + { + // The presence of m_destroyer indicates that the lambda is not trivially destructible + m_destroyer(m_lambda); + } + } + +} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Task/Internal/Task.h b/Code/Framework/AzCore/AzCore/Task/Internal/Task.h new file mode 100644 index 0000000000..e5d3736f2a --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/Internal/Task.h @@ -0,0 +1,180 @@ +/* + * 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 +#include +#include +#include + +namespace AZ::Internal +{ + using TaskInvoke_t = void (*)(void* lambda); + using TaskRelocate_t = void (*)(void* dst, void* src); + using TaskDestroy_t = void (*)(void* obj); + + class CompiledTaskGraph; + + // Lambdas are opaque types and we cannot extract any member function pointers. In order to store lambdas in a + // type erased fashion, we instead use a single function call indirection, invoking the lambda function in a + // static class function which has a stable address in memory. The Erased* methods return addresses to the + // indirect callers of the lambda copy/move assignment operators, call operator, and destructor. + // + // For lambdas that are trivially relocatable, both the returned move and copy assignment function pointers + // will be nullptr. + // + // Lambdas that are trivially destructible will result in a nullptr returned TaskDestroy_t pointer. + // + // The class will check that the lambda is copy assignable or movable. + template + class TaskTypeEraser final + { + public: + constexpr TaskInvoke_t ErasedInvoker() + { + return reinterpret_cast(Invoker); + } + + constexpr TaskRelocate_t ErasedRelocator() + { + if constexpr (AZStd::is_trivially_move_constructible_v) + { + return nullptr; + } + else if constexpr (AZStd::is_move_constructible_v) + { + return reinterpret_cast(Mover); + } + else if constexpr (AZStd::is_copy_constructible_v) + { + return reinterpret_cast(Copier); + } + else + { + static_assert( + AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, + "Task lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " + "constructible."); + } + } + + constexpr TaskDestroy_t ErasedDestroyer() + { + if constexpr (AZStd::is_trivially_destructible_v) + { + return nullptr; + } + else + { + return reinterpret_cast(Destroyer); + } + } + + private: + constexpr static void Invoker(Lambda* lambda) + { + lambda->operator()(); + } + + constexpr static void Mover(Lambda* dst, Lambda* src) + { + new (dst) Lambda{ AZStd::move(*src) }; + } + + constexpr static void Copier(Lambda* dst, Lambda* src) + { + new (dst) Lambda{ *src }; + } + + constexpr static void Destroyer(Lambda* lambda) + { + lambda->~Lambda(); + } + }; + + // The Task encapsulates member function pointers to store in a homogeneously-typed container + // The function signature of all lambdas encoded in a Task is void(*)(). The lambdas can capture + // data, in which case the data is inlined in this structure. Attempting to capture more data + // will result in a compile failure, so use indirection and capture a pointer/reference to your + // data if you run into this. + class alignas(alignof(max_align_t)) Task final + { + public: + AZ_CLASS_ALLOCATOR(Task, ThreadPoolAllocator, 0); + + // The inline buffer allows the Task to span two cache lines. Lambdas can capture 56 + // bytes of data (7 pointers/references on a 64-bit machine). + constexpr static size_t BufferSize = + AZ_TRAIT_TASK_BYTE_SIZE - sizeof(size_t) * 5 - sizeof(uint32_t) - sizeof(TaskDescriptor) - sizeof(AZStd::atomic); + + Task() = default; + + // Prevent binding lvalue references to lambdas + // If you are encountering a compiler error here, please either move the lambda into the AddJob function with AZStd::move + // or simply define the lambda directly as a parameter of AddJob + template + Task(TaskDescriptor const& desc, Lambda& lambda) = delete; + + template + Task(TaskDescriptor const& desc, Lambda&& lambda) noexcept; + + Task(Task&& other) noexcept; + + Task& operator=(Task&& other) noexcept; + + ~Task(); + + void Link(Task& other); + + // Indicates if this task is a root of the graph (with no dependencies) + bool IsRoot() const noexcept; + + // Prepare for dispatch (reset the dependency counter to the number of inbound edges) + void Init() noexcept; + + // Invoke the embedded lambda function + void Invoke(); + + uint8_t GetPriorityNumber() const noexcept; + + private: + friend class CompiledTaskGraph; + friend class TaskWorker; + + // This relocation avoids branches needed if the lambda type is unknown + template + void TypedRelocate(Lambda&& lambda, char* destination); + + // Small buffer optimization for lambdas. We cover our bases here by enforcing alignment on the + // class to equal the alignment of the largest scalar type available on the system (generally + // 16 bytes). + char m_lambda[BufferSize]; + AZStd::atomic m_dependencyCount; + + // This value is an offset in a buffer that stores dependency tracking information. + uint32_t m_successorOffset = 0; + uint32_t m_inboundLinkCount = 0; + uint32_t m_outboundLinkCount = 0; + + CompiledTaskGraph* m_graph = nullptr; + + TaskInvoke_t m_invoker; + + // If nullptr, the lambda is trivially relocatable (via memcpy). Otherwise, it must be invoked + // when instances of this class are moved. + TaskRelocate_t m_relocator; + TaskDestroy_t m_destroyer; + + TaskDescriptor m_descriptor; + }; +} // namespace AZ::Internal + +#include diff --git a/Code/Framework/AzCore/AzCore/Task/Internal/Task.inl b/Code/Framework/AzCore/AzCore/Task/Internal/Task.inl new file mode 100644 index 0000000000..83cd311f56 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/Internal/Task.inl @@ -0,0 +1,84 @@ +/* + * 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 + * + */ + +namespace AZ::Internal +{ + template + Task::Task(TaskDescriptor const& desc, Lambda&& lambda) noexcept + : m_descriptor{ desc } + { + static_assert( + sizeof(Lambda) <= BufferSize, + "Task lambda has too much captured data, please capture no" + "more than 56 bytes of data (likely by capturing a single reference/pointer to a container of data)"); + static_assert( + alignof(Lambda) <= alignof(max_align_t), + "Task lambda has extended alignment which isn't supported." + "Please capture a reference/pointer to the data requiring an extended alignment instead"); + + TaskTypeEraser eraser; + m_invoker = eraser.ErasedInvoker(); + m_relocator = eraser.ErasedRelocator(); + m_destroyer = eraser.ErasedDestroyer(); + + // NOTE: This code is conservative in that extended alignment requirements result in a heap + // spill, even if the lambda could have occupied a portion of the inline buffer with a base + // pointer adjustment. + TypedRelocate(AZStd::forward(lambda), m_lambda); + } + + template + void Task::TypedRelocate(Lambda&& lambda, char* destination) + { + if constexpr (AZStd::is_trivially_move_constructible_v) + { + memcpy(destination, reinterpret_cast(&lambda), sizeof(Lambda)); + } + else if constexpr (AZStd::is_move_constructible_v) + { + new (destination) Lambda{ AZStd::move(lambda) }; + } + else if constexpr (AZStd::is_copy_constructible_v) + { + new (destination) Lambda{ lambda }; + } + else + { + static_assert( + AZStd::is_move_constructible_v || AZStd::is_copy_constructible_v, + "Task lambdas must be either move or copy constructible. Please verify that all captured data is move or copy " + "constructible."); + } + } + + inline void Task::Init() noexcept + { + m_dependencyCount = m_inboundLinkCount; + } + + inline void Task::Invoke() + { + m_invoker(m_lambda); + } + + inline uint8_t Task::GetPriorityNumber() const noexcept + { + return static_cast(m_descriptor.priority); + } + + inline void Task::Link(Task& other) + { + ++m_outboundLinkCount; + ++other.m_inboundLinkCount; + } + + inline bool Task::IsRoot() const noexcept + { + return m_inboundLinkCount == 0; + } +} // namespace AZ::Internal diff --git a/Code/Framework/AzCore/AzCore/Task/Internal/TaskConfig.h b/Code/Framework/AzCore/AzCore/Task/Internal/TaskConfig.h new file mode 100644 index 0000000000..d5550b40d4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/Internal/TaskConfig.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +#if !defined(AZ_TRAIT_TASK_BYTE_SIZE) +#define AZ_TRAIT_TASK_BYTE_SIZE 128 +#endif diff --git a/Code/Framework/AzCore/AzCore/Task/TaskDescriptor.h b/Code/Framework/AzCore/AzCore/Task/TaskDescriptor.h new file mode 100644 index 0000000000..8342fed925 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskDescriptor.h @@ -0,0 +1,49 @@ +/* + * 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 + +namespace AZ +{ + // Task priorities MAY be used judiciously to fine tune runtime execution, with the understanding + // that profiling is needed to understand what the critical path per frame is. Modifying + // task priorities is an EXPERT setting that should succeed a healthy dose of measurement. + enum class TaskPriority : uint8_t + { + CRITICAL = 0, + HIGH = 1, + MEDIUM = 2, // Default + LOW = 3, + PRIORITY_COUNT = 4, + }; + + // All submitted tasks are associated with a TaskDescriptor which defines the priority, affinitization, + // and tracking of the task resource utilization. + // + // TODO: Define various task kinds and provide a mechanism for cpuMask computation on different systems. + struct TaskDescriptor + { + // Unique task kind label (e.g. "frustum culling") + // Task names *must* be provided + const char* taskName = nullptr; + + // Associates a set of task kinds together for budget tracking (e.g. "graphics") + const char* taskGroup = nullptr; + + // EXPERTS ONLY. Tasks of higher priority are executed ahead of any lower priority tasks + // that were queued before it provided they had not yet started + TaskPriority priority = TaskPriority::MEDIUM; + + // EXPERTS ONLY. A bitmask that restricts tasks of this kind to run only on cores + // corresponding to a set bit. 0 is synonymous with all bits set + uint32_t cpuMask = 0; + }; +} diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp similarity index 62% rename from Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp rename to Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index 83823515c1..c69763f289 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -6,8 +6,8 @@ * */ -#include -#include +#include +#include #include #include @@ -17,46 +17,45 @@ #include #include #include +#include #include namespace AZ { - constexpr static size_t PRIORITY_COUNT = static_cast(JobPriority::PRIORITY_COUNT); - namespace Internal { - CompiledJobGraph::CompiledJobGraph( - AZStd::vector&& jobs, + CompiledTaskGraph::CompiledTaskGraph( + AZStd::vector&& tasks, AZStd::unordered_map>& links, size_t linkCount, - JobGraph* parent) + TaskGraph* parent) : m_parent{ parent } { - m_jobs = AZStd::move(jobs); + m_tasks = AZStd::move(tasks); m_successors.resize(linkCount); - TypeErasedJob** cursor = m_successors.data(); + Task** cursor = m_successors.data(); - for (size_t i = 0; i != m_jobs.size(); ++i) + for (size_t i = 0; i != m_tasks.size(); ++i) { - TypeErasedJob& job = m_jobs[i]; - job.m_graph = this; - job.m_successorOffset = cursor - m_successors.data(); - cursor += job.m_outboundLinkCount; + Task& task = m_tasks[i]; + task.m_graph = this; + task.m_successorOffset = cursor - m_successors.data(); + cursor += task.m_outboundLinkCount; - AZ_Assert(job.m_outboundLinkCount == links[i].size(), "Job outbound link information mismatch"); + AZ_Assert(task.m_outboundLinkCount == links[i].size(), "Task outbound link information mismatch"); - for (uint32_t j = 0; j != job.m_outboundLinkCount; ++j) + for (uint32_t j = 0; j != task.m_outboundLinkCount; ++j) { - m_successors[static_cast(job.m_successorOffset) + j] = &m_jobs[links[i][j]]; + m_successors[static_cast(task.m_successorOffset) + j] = &m_tasks[links[i][j]]; } } // TODO: Check for dependency cycles } - uint32_t CompiledJobGraph::Release() + uint32_t CompiledTaskGraph::Release() { uint32_t remaining = --m_remaining; @@ -94,35 +93,35 @@ namespace AZ AZStd::atomic reserve; }; - // The Job Queue is a lock free 4-priority queue. Its basic operation is as follows: + // The Task Queue is a lock free 4-priority queue. Its basic operation is as follows: // Each priority level is associated with a different queue, corresponding to the maximum size of a uint16_t. // Each queue is implemented as a ring buffer, and a 64 bit atomic maintains the following state per queue: // - offset to the "head" of the ring, from where we acquire elements // - offset to the "tail" of the ring, which tracks where new elements should be enqueued // - offset to a tail reservation index, which is used to reserve a slot to enqueue elements - class JobQueue final + class TaskQueue final { public: - // Preallocating upfront allows us to reserve slots to insert jobs without locks. - // Each thread allocated by the job manager consumes ~2 MB. + // Preallocating upfront allows us to reserve slots to insert tasks without locks. + // Each thread allocated by the task manager consumes ~2 MB. constexpr static uint16_t MaxQueueSize = 0xffff; - constexpr static uint8_t PriorityLevelCount = static_cast(JobPriority::PRIORITY_COUNT); + constexpr static uint8_t PriorityLevelCount = static_cast(TaskPriority::PRIORITY_COUNT); - JobQueue() = default; - JobQueue(const JobQueue&) = delete; - JobQueue& operator=(const JobQueue&) = delete; + TaskQueue() = default; + TaskQueue(const TaskQueue&) = delete; + TaskQueue& operator=(const TaskQueue&) = delete; - void Enqueue(TypeErasedJob* job); - TypeErasedJob* TryDequeue(); + void Enqueue(Task* task); + Task* TryDequeue(); private: QueueStatus m_status[PriorityLevelCount] = {}; - TypeErasedJob* m_queues[PriorityLevelCount][MaxQueueSize] = {}; + Task* m_queues[PriorityLevelCount][MaxQueueSize] = {}; }; - void JobQueue::Enqueue(TypeErasedJob* job) + void TaskQueue::Enqueue(Task* task) { - uint8_t priority = job->GetPriorityNumber(); + uint8_t priority = task->GetPriorityNumber(); QueueStatus& status = m_status[priority]; AZStd::exponential_backoff backoff; @@ -131,18 +130,18 @@ namespace AZ uint16_t reserve = status.reserve.load(); uint16_t head = status.head.load(); - // Enqueuing is done in two phases because we cannot atomically write the job to the slot we reserve + // Enqueuing is done in two phases because we cannot atomically write the task to the slot we reserve // and simulataneously publish the fact that the slot is now available. if (reserve != head - 1) { // Try to reserve a slot if (status.reserve.compare_exchange_weak(reserve, reserve + 1)) { - m_queues[priority][reserve] = job; + m_queues[priority][reserve] = task; uint16_t expectedReserve = reserve; - // Increment the tail to advertise the new job + // Increment the tail to advertise the new task while (!status.tail.compare_exchange_weak(expectedReserve, reserve + 1)) { expectedReserve = reserve; @@ -160,7 +159,7 @@ namespace AZ } } - TypeErasedJob* JobQueue::TryDequeue() + Task* TaskQueue::TryDequeue() { for (size_t priority = 0; priority != PriorityLevelCount; ++priority) { @@ -176,10 +175,10 @@ namespace AZ } else { - TypeErasedJob* job = m_queues[priority][status.head]; + Task* task = m_queues[priority][status.head]; if (status.head.compare_exchange_weak(head, head + 1)) { - return job; + return task; } } } @@ -188,14 +187,14 @@ namespace AZ return nullptr; } - class JobWorker + class TaskWorker { public: - void Spawn(::AZ::JobExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize) + void Spawn(::AZ::TaskExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize) { m_executor = &executor; - AZStd::string threadName = AZStd::string::format("JobWorker %zu", id); + AZStd::string threadName = AZStd::string::format("TaskWorker %zu", id); AZStd::thread_desc desc = {}; desc.m_name = threadName.c_str(); if (affinitize) @@ -219,13 +218,13 @@ namespace AZ m_thread.join(); } - void Enqueue(TypeErasedJob* job) + void Enqueue(Task* task) { - m_queue.Enqueue(job); + m_queue.Enqueue(task); if (!m_busy.exchange(true)) { - // The worker was idle prior to enqueueing the job, release the semaphore + // The worker was idle prior to enqueueing the task, release the semaphore m_semaphore.release(); } } @@ -245,24 +244,26 @@ namespace AZ m_busy = true; - TypeErasedJob* job = m_queue.TryDequeue(); - while (job) + Task* task = m_queue.TryDequeue(); + while (task) { - job->Invoke(); - // Decrement counts for all job successors - for (size_t j = 0; j != job->m_outboundLinkCount; ++j) + task->Invoke(); + // Decrement counts for all task successors + for (size_t j = 0; j != task->m_outboundLinkCount; ++j) { - TypeErasedJob* successor = job->m_graph->m_successors[job->m_successorOffset + j]; + Task* successor = task->m_graph->m_successors[task->m_successorOffset + j]; if (--successor->m_dependencyCount == 0) { m_executor->Submit(*successor); } } - job->m_graph->Release(); - --m_executor->m_remaining; + if (task->m_graph->Release() == (task->m_graph->m_parent ? 1 : 0)) + { + m_executor->ReleaseGraph(); + } - job = m_queue.TryDequeue(); + task = m_queue.TryDequeue(); } } } @@ -272,24 +273,38 @@ namespace AZ AZStd::atomic m_busy; AZStd::binary_semaphore m_semaphore; - ::AZ::JobExecutor* m_executor; - JobQueue m_queue; + ::AZ::TaskExecutor* m_executor; + TaskQueue m_queue; }; } // namespace Internal - JobExecutor& JobExecutor::Instance() + static EnvironmentVariable s_executor; + constexpr static const char* s_executorName = "GlobalTaskExecutor"; + TaskExecutor& TaskExecutor::Instance() { - // TODO: Create the default executor as part of a component (as in JobManagerComponent) - static JobExecutor executor; - return executor; + if (!s_executor) + { + s_executor = AZ::Environment::FindVariable(s_executorName); + } + + return **s_executor; } - JobExecutor::JobExecutor(uint32_t threadCount) + // TODO: Create the default executor as part of a component (as in TaskManagerComponent) + void TaskExecutor::SetInstance(TaskExecutor* executor) + { + AZ_Assert(!s_executor, "Attempting to set the global task executor more than once"); + + s_executor = AZ::Environment::CreateVariable("GlobalTaskExecutor"); + s_executor.Set(executor); + } + + TaskExecutor::TaskExecutor(uint32_t threadCount) { // TODO: Configure thread count + affinity based on configuration m_threadCount = threadCount == 0 ? AZStd::thread::hardware_concurrency() : threadCount; - m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::JobWorker))); + m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::TaskWorker))); bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency(); @@ -297,7 +312,7 @@ namespace AZ for (size_t i = 0; i != m_threadCount; ++i) { - new (m_workers + i) Internal::JobWorker{}; + new (m_workers + i) Internal::TaskWorker{}; m_workers[i].Spawn(*this, i, initSemaphore, affinitize); } @@ -307,43 +322,56 @@ namespace AZ } } - JobExecutor::~JobExecutor() + TaskExecutor::~TaskExecutor() { for (size_t i = 0; i != m_threadCount; ++i) { m_workers[i].Join(); - m_workers[i].~JobWorker(); + m_workers[i].~TaskWorker(); } azfree(m_workers); } - void JobExecutor::Submit(Internal::CompiledJobGraph& graph) + void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph) { - // Submit all jobs that have no inbound edges - for (Internal::TypeErasedJob& job : graph.Jobs()) + ++m_graphsRemaining; + // Submit all tasks that have no inbound edges + for (Internal::Task& task : graph.Tasks()) { - if (job.IsRoot()) + if (task.IsRoot()) { - Submit(job); + Submit(task); } } } - void JobExecutor::Submit(Internal::TypeErasedJob& job) + void TaskExecutor::Submit(Internal::Task& task) { // TODO: Something more sophisticated is likely needed here. // First, we are completely ignoring affinity. // Second, some heuristics on core availability will help distribute work more effectively - ++m_remaining; - m_workers[++m_lastSubmission % m_threadCount].Enqueue(&job); + m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task); } - void JobExecutor::Drain() + void TaskExecutor::Drain() { - while (m_remaining > 0) + m_isDraining = true; + if (m_graphsRemaining == 0) { - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds{ 100 }); + return; + } + m_drainSemaphore.acquire(); + } + + void TaskExecutor::ReleaseGraph() + { + uint64_t graphsRemaining = --m_graphsRemaining; + + if (graphsRemaining == 0 && m_isDraining) + { + m_drainSemaphore.release(); + m_isDraining = false; } } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h new file mode 100644 index 0000000000..ad4c4b81c2 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h @@ -0,0 +1,94 @@ +/* + * 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 +#include +#include +#include + +namespace AZ +{ + class TaskGraphEvent; + class TaskGraph; + + namespace Internal + { + class CompiledTaskGraph final + { + public: + AZ_CLASS_ALLOCATOR(CompiledTaskGraph, SystemAllocator, 0) + + CompiledTaskGraph( + AZStd::vector&& tasks, + AZStd::unordered_map>& links, + size_t linkCount, + TaskGraph* parent); + + AZStd::vector& Tasks() noexcept + { + return m_tasks; + } + + // Indicate that a constituent task has finished and decrement a counter to determine if the + // graph should be freed (returns the value after atomic decrement) + uint32_t Release(); + + private: + friend class ::AZ::TaskGraph; + friend class TaskWorker; + + AZStd::vector m_tasks; + AZStd::vector m_successors; + TaskGraphEvent* m_waitEvent = nullptr; + // The pointer to the parent graph is set only if it is retained + TaskGraph* m_parent = nullptr; + AZStd::atomic m_remaining; + }; + + class TaskWorker; + } // namespace Internal + + class TaskExecutor final + { + public: + AZ_CLASS_ALLOCATOR(TaskExecutor, SystemAllocator, 0); + + static TaskExecutor& Instance(); + + // Invoked by a system component on program launch + static void SetInstance(TaskExecutor* executor); + + // Passing 0 for the threadCount requests for the thread count to match the hardware concurrency + explicit TaskExecutor(uint32_t threadCount = 0); + ~TaskExecutor(); + + void Submit(Internal::CompiledTaskGraph& graph); + + void Submit(Internal::Task& task); + + // Wait until tasks are cleared from the executor (note, does not prevent future tasks from being submitted) + // If this is used, it's expected to be used between frames to shutdown the engine + void Drain(); + private: + friend class Internal::TaskWorker; + + void ReleaseGraph(); + + Internal::TaskWorker* m_workers; + uint32_t m_threadCount = 0; + AZStd::atomic m_lastSubmission; + AZStd::atomic m_graphsRemaining; + AZStd::atomic m_isDraining; + AZStd::binary_semaphore m_drainSemaphore; + }; +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp new file mode 100644 index 0000000000..86e4f846d5 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp @@ -0,0 +1,85 @@ +/* + * 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 + +namespace AZ +{ + using Internal::CompiledTaskGraph; + + void TaskToken::PrecedesInternal(TaskToken& comesAfter) + { + AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted."); + + // Increment inbound/outbound edge counts + m_parent.m_tasks[m_index].Link(m_parent.m_tasks[comesAfter.m_index]); + + m_parent.m_links[m_index].emplace_back(comesAfter.m_index); + + ++m_parent.m_linkCount; + } + + TaskGraph::~TaskGraph() + { + if (m_retained && m_compiledTaskGraph) + { + // This job graph has already finished and we are potentially responsible for its destruction + if (m_compiledTaskGraph->Release() == 0) + { + azdestroy(m_compiledTaskGraph); + } + } + } + + void TaskGraph::Reset() + { + AZ_Assert(!m_submitted, "Cannot reset a job graph while it is in flight"); + if (m_compiledTaskGraph) + { + azdestroy(m_compiledTaskGraph); + m_compiledTaskGraph = nullptr; + } + m_tasks.clear(); + m_links.clear(); + m_linkCount = 0; + } + + void TaskGraph::Submit(TaskGraphEvent* waitEvent) + { + SubmitOnExecutor(TaskExecutor::Instance(), waitEvent); + } + + void TaskGraph::SubmitOnExecutor(TaskExecutor& executor, TaskGraphEvent* waitEvent) + { + if (!m_compiledTaskGraph) + { + m_compiledTaskGraph = aznew CompiledTaskGraph(AZStd::move(m_tasks), m_links, m_linkCount, m_retained ? this : nullptr); + } + + m_compiledTaskGraph->m_waitEvent = waitEvent; + m_compiledTaskGraph->m_remaining = m_compiledTaskGraph->m_tasks.size() + (m_retained ? 1 : 0); + for (size_t i = 0; i != m_compiledTaskGraph->m_tasks.size(); ++i) + { + m_compiledTaskGraph->m_tasks[i].Init(); + } + + executor.Submit(*m_compiledTaskGraph); + + if (m_retained) + { + m_submitted = true; + } + else + { + m_compiledTaskGraph = nullptr; + Reset(); + } + } +} diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h new file mode 100644 index 0000000000..d133593508 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h @@ -0,0 +1,151 @@ +/* + * 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 + +// NOTE: If adding additional header/symbol dependencies, consider if such additions are better +// suited in the private CompiledTaskGraph implementation instead to keep this header lean. +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Internal + { + class CompiledTaskGraph; + } + class TaskExecutor; + class TaskGraph; + + // A TaskToken is returned each time a Task is added to the TaskGraph. TaskTokens are used to + // express dependencies between tasks within the graph, and have no purpose after the graph + // is submitted (simply let them go out of scope) + class TaskToken final + { + public: + // Indicate that this task must finish before the task token(s) passed as the argument + template + void Precedes(JT&... tokens); + + // Indicate that this task must finish after the task token(s) passed as the argument + template + void Follows(JT&... tokens); + + private: + friend class TaskGraph; + + void PrecedesInternal(TaskToken& comesAfter); + + // Only the TaskGraph should be creating TaskToken + TaskToken(TaskGraph& parent, size_t index); + + TaskGraph& m_parent; + size_t m_index; + }; + + // A TaskGraphEvent may be used to block until a task graph has finished executing. Usage + // is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting + // the graph without synchronization over the course of the frame). However, the event + // is useful for the edges of the computation graph. + // + // You are responsible for ensuring the event object lifetime exceeds the task graph lifetime. + // + // After the TaskGraphEvent is signaled, you are allowed to reuse the same TaskGraphEvent + // for a future submission. + class TaskGraphEvent + { + public: + bool IsSignaled(); + void Wait(); + + private: + friend class ::AZ::Internal::CompiledTaskGraph; + friend class TaskGraph; + void Signal(); + + AZStd::binary_semaphore m_semaphore; + }; + + // The TaskGraph encapsulates a set of tasks and their interdependencies. After adding + // tasks, and marking dependencies as necessary, the entire graph is submitted via + // the TaskGraph::Submit method. + // + // The TaskGraph MAY be retained across multiple frames and resubmitted, provided the + // user provides some guarantees (see comments associated with TaskGraph::Retain). + class TaskGraph final + { + public: + ~TaskGraph(); + + // Reset the state of the task graph to begin recording tasks and edges again + // NOTE: Graph must be in a "settled" state (cannot be in-flight) + void Reset(); + + // Add a task to the graph, retrieiving a token that can be used to express dependencies + // between tasks. The first argument specifies the TaskKind, used for tracking the task. + // NOTE: This operation is invalid if the graph is in-flight + template + TaskToken AddTask(TaskDescriptor const& descriptor, Lambda&& lambda); + + template + AZStd::array AddTasks(TaskDescriptor const& descriptor, Lambdas&&... lambdas); + + // By default, you are responsible for retaining the TaskGraph, indicating you promise that + // this TaskGraph will live as long as it takes for all constituent tasks to complete. + // Once retained, this task graph can be resubmitted after completion without any + // modifications. TaskTokens that were created as a result of adding tasks used to + // mark dependencies DO NOT need to outlive the task graph. + // + // Invoking Detach PRIOR to submission indicates you wish the tasks associated with this + // TaskGraph to deallocate upon completion. After invoking Detach, you may let this TaskGraph + // go out of scope or deallocate after submission. + // + // NOTE: The TaskGraph has no concept of resources used by design. Resubmission + // of the task graph is expected to rely on either indirection, or safe overwriting + // of previously used memory to supply new data (this can even be done as the first + // task in the graph). + // NOTE: This operation is invalid if the graph is in-flight + void Detach(); + + // Invoke the task graph, asserting if there are dependency violations. Note that + // submitting the same graph multiple times to process simultaneously is VALID + // behavior. This is, for example, a mechanism that allows a task graph to loop + // in perpetuity (in fact, the entire frame could be modeled as a single task graph, + // where the final task resubmits the task graph again). + // + // This API is not designed to protect against memory safety violations (nothing + // can prevent a user from incorrectly aliasing memory unsafely even without repeated + // submission). To catch memory safety violations, it is ENCOURAGED that you access + // data through TaskResource handles. + void Submit(TaskGraphEvent* waitEvent = nullptr); + + // Same as submit but run on a different executor than the default system executor + void SubmitOnExecutor(TaskExecutor& executor, TaskGraphEvent* waitEvent = nullptr); + + private: + friend class TaskToken; + friend class Internal::CompiledTaskGraph; + + Internal::CompiledTaskGraph* m_compiledTaskGraph = nullptr; + + AZStd::vector m_tasks; + + // Task index |-> Dependent task indices + AZStd::unordered_map> m_links; + + uint32_t m_linkCount = 0; + bool m_retained = true; + AZStd::atomic m_submitted = false; + }; +} // namespace AZ + +#include diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl similarity index 50% rename from Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl rename to Code/Framework/AzCore/AzCore/Task/TaskGraph.inl index ad1fb3505c..1971ddbbca 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobGraph.inl +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl @@ -10,56 +10,56 @@ namespace AZ { - inline JobToken::JobToken(JobGraph& parent, size_t index) + inline TaskToken::TaskToken(TaskGraph& parent, size_t index) : m_parent{ parent } , m_index{ index } { } template - inline void JobToken::Precedes(JT&... tokens) + void TaskToken::Precedes(JT&... tokens) { (PrecedesInternal(tokens), ...); } template - inline void JobToken::Succeeds(JT&... tokens) + void TaskToken::Follows(JT&... tokens) { (tokens.PrecedesInternal(*this), ...); } - inline bool JobGraphEvent::IsSignaled() + inline bool TaskGraphEvent::IsSignaled() { return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 }); } - inline void JobGraphEvent::Wait() + inline void TaskGraphEvent::Wait() { m_semaphore.acquire(); } - inline void JobGraphEvent::Signal() + inline void TaskGraphEvent::Signal() { m_semaphore.release(); } template - inline JobToken JobGraph::AddJob(JobDescriptor const& desc, Lambda&& lambda) + TaskToken TaskGraph::AddTask(TaskDescriptor const& desc, Lambda&& lambda) { - AZ_Assert(!m_submitted, "Cannot mutate a JobGraph that was previously submitted or in flight."); + AZ_Assert(!m_submitted, "Cannot mutate a TaskGraph that was previously submitted or in flight."); - m_jobs.emplace_back(desc, AZStd::forward(lambda)); + m_tasks.emplace_back(desc, AZStd::forward(lambda)); - return { *this, m_jobs.size() - 1 }; + return { *this, m_tasks.size() - 1 }; } template - inline AZStd::array JobGraph::AddJobs(JobDescriptor const& descriptor, Lambdas&&... lambdas) + AZStd::array TaskGraph::AddTasks(TaskDescriptor const& descriptor, Lambdas&&... lambdas) { - return { AddJob(descriptor, AZStd::forward(lambdas))... }; + return { AddTask(descriptor, AZStd::forward(lambdas))... }; } - inline void JobGraph::Detach() + inline void TaskGraph::Detach() { m_retained = false; } diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index a23ec9ab82..1e2a0b98a0 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -221,8 +221,6 @@ set(FILES Jobs/Internal/JobManagerWorkStealing.cpp Jobs/Internal/JobManagerWorkStealing.h Jobs/Internal/JobNotify.h - Jobs/Internal/JobTypeEraser.cpp - Jobs/Internal/JobTypeEraser.h Jobs/Job.cpp Jobs/Job.h Jobs/JobCancelGroup.h @@ -230,14 +228,8 @@ set(FILES Jobs/JobCompletionSpin.h Jobs/JobContext.cpp Jobs/JobContext.h - Jobs/JobDescriptor.h Jobs/JobEmpty.h - Jobs/JobExecutor.cpp - Jobs/JobExecutor.h Jobs/JobFunction.h - Jobs/JobGraph.cpp - Jobs/JobGraph.h - Jobs/JobGraph.inl Jobs/JobManager.cpp Jobs/JobManager.h Jobs/JobManagerBus.h @@ -624,6 +616,16 @@ set(FILES Socket/AzSocket_fwd.h Socket/AzSocket.cpp Socket/AzSocket.h + Task/Internal/Task.cpp + Task/Internal/Task.inl + Task/Internal/Task.h + Task/Internal/TaskConfig.h + Task/TaskDescriptor.h + Task/TaskExecutor.cpp + Task/TaskExecutor.h + Task/TaskGraph.cpp + Task/TaskGraph.h + Task/TaskGraph.inl Threading/ThreadSafeDeque.h Threading/ThreadSafeDeque.inl Threading/ThreadSafeObject.h diff --git a/Code/Framework/AzCore/Tests/JobGraphTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp similarity index 53% rename from Code/Framework/AzCore/Tests/JobGraphTests.cpp rename to Code/Framework/AzCore/Tests/TaskTests.cpp index 469773f471..eeb523ae26 100644 --- a/Code/Framework/AzCore/Tests/JobGraphTests.cpp +++ b/Code/Framework/AzCore/Tests/TaskTests.cpp @@ -6,26 +6,26 @@ * */ -#include -#include +#include +#include #include #include #include -using AZ::JobDescriptor; -using AZ::JobGraph; -using AZ::JobGraphEvent; -using AZ::JobExecutor; -using AZ::Internal::TypeErasedJob; -using AZ::JobPriority; +using AZ::TaskDescriptor; +using AZ::TaskGraph; +using AZ::TaskGraphEvent; +using AZ::TaskExecutor; +using AZ::Internal::Task; +using AZ::TaskPriority; -static JobDescriptor defaultJD{ "JobGraphTestJob", "JobGraphTests" }; +static TaskDescriptor defaultTD{ "TaskGraphTestTask", "TaskGraphTests" }; namespace UnitTest { - class JobGraphTestFixture : public AllocatorsTestFixture + class TaskGraphTestFixture : public AllocatorsTestFixture { public: void SetUp() override @@ -34,7 +34,7 @@ namespace UnitTest AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); - m_executor = aznew JobExecutor(4); + m_executor = aznew TaskExecutor(4); } void TearDown() override @@ -46,38 +46,38 @@ namespace UnitTest } protected: - JobExecutor* m_executor; + TaskExecutor* m_executor; }; - TEST(JobGraphTests, TrivialJobLambda) + TEST(TaskGraphTests, TrivialTaskLambda) { int x = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [&x]() { ++x; }); - job.Invoke(); + task.Invoke(); EXPECT_EQ(1, x); } - TEST(JobGraphTests, TrivialJobLambdaMove) + TEST(TaskGraphTests, TrivialTaskLambdaMove) { int x = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [&x]() { ++x; }); - TypeErasedJob job2 = AZStd::move(job); + Task task2 = AZStd::move(task); - job2.Invoke(); + task2.Invoke(); EXPECT_EQ(1, x); } @@ -110,78 +110,90 @@ namespace UnitTest int copyCount = 0; }; - TEST(JobGraphTests, MoveOnlyJobLambda) + /* + TEST(TaskGraphTests, ThisShouldNotCompile) + { + auto lambda = [] + { + }; + + Task task(defaultTD, lambda); + task.Invoke(); + } + */ + + TEST(TaskGraphTests, MoveOnlyTaskLambda) { TrackMoves tm; int moveCount = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [tm = AZStd::move(tm), &moveCount] { moveCount = tm.moveCount; }); - job.Invoke(); + task.Invoke(); // Two moves are expected. Once into the capture body of the lambda, once to construct - // the type erased job + // the type erased task EXPECT_EQ(2, moveCount); } - TEST(JobGraphTests, MoveOnlyJobLambdaMove) + TEST(TaskGraphTests, MoveOnlyTaskLambdaMove) { TrackMoves tm; int moveCount = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [tm = AZStd::move(tm), &moveCount] { moveCount = tm.moveCount; }); - TypeErasedJob job2 = AZStd::move(job); - job2.Invoke(); + Task task2 = AZStd::move(task); + task2.Invoke(); EXPECT_EQ(3, moveCount); } - TEST(JobGraphTests, CopyOnlyJobLambda) + TEST(TaskGraphTests, CopyOnlyTaskLambda) { TrackCopies tc; int copyCount = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [tc, ©Count] { copyCount = tc.copyCount; }); - job.Invoke(); + task.Invoke(); // Two copies are expected. Once into the capture body of the lambda, once to construct - // the type erased job + // the type erased task EXPECT_EQ(2, copyCount); } - TEST(JobGraphTests, CopyOnlyJobLambdaMove) + TEST(TaskGraphTests, CopyOnlyTaskLambdaMove) { TrackCopies tc; int copyCount = 0; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [tc, ©Count] { copyCount = tc.copyCount; }); - TypeErasedJob job2 = AZStd::move(job); - job2.Invoke(); + Task task2 = AZStd::move(task); + task2.Invoke(); EXPECT_EQ(3, copyCount); } - TEST(JobGraphTests, DestroyLambda) + TEST(TaskGraphTests, DestroyLambda) { // This test ensures that for a lambda with a destructor, the destructor is invoked // exactly once on a non-moved-from object. @@ -209,12 +221,12 @@ namespace UnitTest { TrackDestroy td{ &x }; - TypeErasedJob job( - defaultJD, + Task task( + defaultTD, [td = AZStd::move(td)] { }); - job.Invoke(); + task.Invoke(); // Destructor should not have run yet (except on moved-from instances) EXPECT_EQ(x, 0); } @@ -223,25 +235,21 @@ namespace UnitTest EXPECT_EQ(x, 1); } - TEST_F(JobGraphTestFixture, SerialGraph) + TEST_F(TaskGraphTestFixture, VariadicInterface) { int x = 0; - JobGraph graph; - auto a = graph.AddJob( - defaultJD, + TaskGraph graph; + auto [a, b, c] = graph.AddTasks( + defaultTD, [&] { x += 3; - }); - auto b = graph.AddJob( - defaultJD, + }, [&] { x = 4 * x; - }); - auto c = graph.AddJob( - defaultJD, + }, [&] { x -= 1; @@ -250,35 +258,69 @@ namespace UnitTest a.Precedes(b); b.Precedes(c); - JobGraphEvent ev; + TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); EXPECT_EQ(11, x); } - TEST_F(JobGraphTestFixture, DetachedGraph) + TEST_F(TaskGraphTestFixture, SerialGraph) { int x = 0; - JobGraphEvent ev; + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, + [&] + { + x += 3; + }); + auto b = graph.AddTask( + defaultTD, + [&] + { + x = 4 * x; + }); + auto c = graph.AddTask( + defaultTD, + [&] + { + x -= 1; + }); + + a.Precedes(b); + b.Precedes(c); + + TaskGraphEvent ev; + graph.SubmitOnExecutor(*m_executor, &ev); + ev.Wait(); + + EXPECT_EQ(11, x); + } + + TEST_F(TaskGraphTestFixture, DetachedGraph) + { + int x = 0; + + TaskGraphEvent ev; { - JobGraph graph; - auto a = graph.AddJob( - defaultJD, + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, [&] { x += 3; }); - auto b = graph.AddJob( - defaultJD, + auto b = graph.AddTask( + defaultTD, [&] { x = 4 * x; }); - auto c = graph.AddJob( - defaultJD, + auto c = graph.AddTask( + defaultTD, [&] { x -= 1; @@ -295,35 +337,35 @@ namespace UnitTest EXPECT_EQ(11, x); } - TEST_F(JobGraphTestFixture, ForkJoin) + TEST_F(TaskGraphTestFixture, ForkJoin) { AZStd::atomic x = 0; - // Job a initializes x to 3 - // Job b and c toggles the lowest two bits atomically - // Job d decrements x + // Task a initializes x to 3 + // Task b and c toggles the lowest two bits atomically + // Task d decrements x - JobGraph graph; - auto a = graph.AddJob( - defaultJD, + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, [&] { x = 0b111; }); - auto b = graph.AddJob( - defaultJD, + auto b = graph.AddTask( + defaultTD, [&] { x ^= 1; }); - auto c = graph.AddJob( - defaultJD, + auto c = graph.AddTask( + defaultTD, [&] { x ^= 2; }); - auto d = graph.AddJob( - defaultJD, + auto d = graph.AddTask( + defaultTD, [&] { x -= 1; @@ -336,65 +378,65 @@ namespace UnitTest // d a.Precedes(b, c); - d.Succeeds(b, c); + d.Follows(b, c); - JobGraphEvent ev; + TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); EXPECT_EQ(3, x); } - TEST_F(JobGraphTestFixture, SpawnSubgraph) + TEST_F(TaskGraphTestFixture, SpawnSubgraph) { AZStd::atomic x = 0; - JobGraph graph; - auto a = graph.AddJob( - defaultJD, + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, [&] { x = 0b111; }); - auto b = graph.AddJob( - defaultJD, + auto b = graph.AddTask( + defaultTD, [&] { x ^= 1; }); - auto c = graph.AddJob( - defaultJD, + auto c = graph.AddTask( + defaultTD, [&] { x ^= 2; - JobGraph subgraph; - auto e = subgraph.AddJob( - defaultJD, + TaskGraph subgraph; + auto e = subgraph.AddTask( + defaultTD, [&] { x ^= 0b1000; }); - auto f = subgraph.AddJob( - defaultJD, + auto f = subgraph.AddTask( + defaultTD, [&] { x ^= 0b10000; }); - auto g = subgraph.AddJob( - defaultJD, + auto g = subgraph.AddTask( + defaultTD, [&] { x += 0b1000; }); e.Precedes(g); f.Precedes(g); - JobGraphEvent ev; + TaskGraphEvent ev; subgraph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); }); - auto d = graph.AddJob( - defaultJD, + auto d = graph.AddTask( + defaultTD, [&] { x -= 1; @@ -418,56 +460,56 @@ namespace UnitTest b.Precedes(d); c.Precedes(d); - JobGraphEvent ev; + TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); EXPECT_EQ(3 | 0b100000, x); } - TEST_F(JobGraphTestFixture, RetainedGraph) + TEST_F(TaskGraphTestFixture, RetainedGraph) { AZStd::atomic x = 0; - JobGraph graph; - auto a = graph.AddJob( - defaultJD, + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, [&] { x = 0b111; }); - auto b = graph.AddJob( - defaultJD, + auto b = graph.AddTask( + defaultTD, [&] { x ^= 1; }); - auto c = graph.AddJob( - defaultJD, + auto c = graph.AddTask( + defaultTD, [&] { x ^= 2; }); - auto d = graph.AddJob( - defaultJD, + auto d = graph.AddTask( + defaultTD, [&] { x -= 1; }); - auto e = graph.AddJob( - defaultJD, + auto e = graph.AddTask( + defaultTD, [&] { x ^= 0b1000; }); - auto f = graph.AddJob( - defaultJD, + auto f = graph.AddTask( + defaultTD, [&] { x ^= 0b10000; }); - auto g = graph.AddJob( - defaultJD, + auto g = graph.AddTask( + defaultTD, [&] { x += 0b1000; @@ -486,10 +528,10 @@ namespace UnitTest a.Precedes(b, c); b.Precedes(d); c.Precedes(e, f); - g.Succeeds(e, f); + g.Follows(e, f); g.Precedes(d); - JobGraphEvent ev; + TaskGraphEvent ev; graph.SubmitOnExecutor(*m_executor, &ev); ev.Wait(); @@ -501,18 +543,107 @@ namespace UnitTest EXPECT_EQ(3 | 0b100000, x); } + + TEST_F(TaskGraphTestFixture, ExecutorDrainRetained) + { + bool drainDone = false; + AZStd::binary_semaphore taskStart; + AZStd::binary_semaphore threadLaunched; + AZStd::binary_semaphore threadFinished; + + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, + [&] + { + taskStart.acquire(); + }); + + graph.SubmitOnExecutor(*m_executor); + + AZStd::thread drainThread{ [this, &drainDone, &threadLaunched, &threadFinished] + { + threadLaunched.release(); + m_executor->Drain(); + drainDone = true; + threadFinished.release(); + } }; + + + // Wait until our drain thread has launched + threadLaunched.acquire(); + + // The task itself hasn't started, so the drain should still be blocking + EXPECT_EQ(false, drainDone); + + // Allow the task to finish + taskStart.release(); + + // Wait for the drain thread to wrap up + threadFinished.acquire(); + + // We successfully drained the executor + EXPECT_EQ(true, drainDone); + + drainThread.join(); + } + + TEST_F(TaskGraphTestFixture, ExecutorDrainDetached) + { + bool drainDone = false; + AZStd::binary_semaphore taskStart; + AZStd::binary_semaphore threadLaunched; + AZStd::binary_semaphore threadFinished; + + TaskGraph graph; + auto a = graph.AddTask( + defaultTD, + [&] + { + taskStart.acquire(); + }); + graph.Detach(); + + graph.SubmitOnExecutor(*m_executor); + + AZStd::thread drainThread{ [this, &drainDone, &threadLaunched, &threadFinished] + { + threadLaunched.release(); + m_executor->Drain(); + drainDone = true; + threadFinished.release(); + } }; + + + // Wait until our drain thread has launched + threadLaunched.acquire(); + + // The task itself hasn't started, so the drain should still be blocking + EXPECT_EQ(false, drainDone); + + // Allow the task to finish + taskStart.release(); + + // Wait for the drain thread to wrap up + threadFinished.acquire(); + + // We successfully drained the executor + EXPECT_EQ(true, drainDone); + + drainThread.join(); + } } // namespace UnitTest #if defined(HAVE_BENCHMARK) namespace Benchmark { - class JobGraphBenchmarkFixture : public ::benchmark::Fixture + class TaskGraphBenchmarkFixture : public ::benchmark::Fixture { public: void SetUp(benchmark::State&) override { - executor = new JobExecutor; - graph = new JobGraph; + executor = new TaskExecutor; + graph = new TaskGraph; } void TearDown(benchmark::State&) override @@ -521,38 +652,38 @@ namespace Benchmark delete executor; } - JobDescriptor descriptors[4] = { { "critical", "benchmark", JobPriority::CRITICAL }, - { "high", "benchmark", JobPriority::HIGH }, - { "medium", "benchmark", JobPriority::MEDIUM }, - { "low", "benchmark", JobPriority::LOW } }; + TaskDescriptor descriptors[4] = { { "critical", "benchmark", TaskPriority::CRITICAL }, + { "high", "benchmark", TaskPriority::HIGH }, + { "medium", "benchmark", TaskPriority::MEDIUM }, + { "low", "benchmark", TaskPriority::LOW } }; - JobGraph* graph; - JobExecutor* executor; + TaskGraph* graph; + TaskExecutor* executor; }; - BENCHMARK_F(JobGraphBenchmarkFixture, QueueToDequeue)(benchmark::State& state) + BENCHMARK_F(TaskGraphBenchmarkFixture, QueueToDequeue)(benchmark::State& state) { - graph->AddJob( + graph->AddTask( descriptors[2], [] { }); for (auto _ : state) { - JobGraphEvent ev; + TaskGraphEvent ev; graph->SubmitOnExecutor(*executor, &ev); ev.Wait(); } } - BENCHMARK_F(JobGraphBenchmarkFixture, OneAfterAnother)(benchmark::State& state) + BENCHMARK_F(TaskGraphBenchmarkFixture, OneAfterAnother)(benchmark::State& state) { - auto a = graph->AddJob( + auto a = graph->AddTask( descriptors[2], [] { }); - auto b = graph->AddJob( + auto b = graph->AddTask( descriptors[2], [] { @@ -561,15 +692,15 @@ namespace Benchmark for (auto _ : state) { - JobGraphEvent ev; + TaskGraphEvent ev; graph->SubmitOnExecutor(*executor, &ev); ev.Wait(); } } - BENCHMARK_F(JobGraphBenchmarkFixture, FourToOneJoin)(benchmark::State& state) + BENCHMARK_F(TaskGraphBenchmarkFixture, FourToOneJoin)(benchmark::State& state) { - auto [a, b, c, d, e] = graph->AddJobs( + auto [a, b, c, d, e] = graph->AddTasks( descriptors[2], [] { @@ -587,11 +718,11 @@ namespace Benchmark { }); - e.Succeeds(a, b, c, d); + e.Follows(a, b, c, d); for (auto _ : state) { - JobGraphEvent ev; + TaskGraphEvent ev; graph->SubmitOnExecutor(*executor, &ev); ev.Wait(); } diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 480baabe7a..ca0e2862fc 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -40,7 +40,6 @@ set(FILES Interface.cpp IO/Path/PathTests.cpp IPC.cpp - JobGraphTests.cpp Jobs.cpp JSON.cpp FixedWidthIntegers.cpp @@ -66,6 +65,7 @@ set(FILES StreamerTests.cpp StringFunc.cpp SystemFile.cpp + TaskTests.cpp TickBusTest.cpp TimeDataStatistics.cpp UUIDTests.cpp From 4743ca8bc1d24e24d7d0f6171dc8f5baf858804e Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Thu, 5 Aug 2021 17:32:57 -0600 Subject: [PATCH 11/18] Fix segfault when checking detached graph completion status Signed-off-by: Jeremy Ong --- Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index c69763f289..e8b4735243 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -258,7 +258,8 @@ namespace AZ } } - if (task->m_graph->Release() == (task->m_graph->m_parent ? 1 : 0)) + bool isRetained = task->m_graph->m_parent != nullptr; + if (task->m_graph->Release() == (isRetained ? 1 : 0)) { m_executor->ReleaseGraph(); } From 4f9c2cf693924ec7732eed591d53937ef869bd50 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Fri, 6 Aug 2021 03:02:41 -0600 Subject: [PATCH 12/18] Remove TaskGraph::Drain which was only added initially for testing The drain function was used only before the API gained the ability to wait on the completion of a graph. This is the correct way to "drain" the task executor of work. Signed-off-by: Jeremy Ong --- .../AzCore/AzCore/Task/TaskExecutor.cpp | 18 +--- .../AzCore/AzCore/Task/TaskExecutor.h | 5 -- Code/Framework/AzCore/Tests/TaskTests.cpp | 89 ------------------- 3 files changed, 1 insertion(+), 111 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index e8b4735243..293b88b2e6 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -355,24 +355,8 @@ namespace AZ m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task); } - void TaskExecutor::Drain() - { - m_isDraining = true; - if (m_graphsRemaining == 0) - { - return; - } - m_drainSemaphore.acquire(); - } - void TaskExecutor::ReleaseGraph() { - uint64_t graphsRemaining = --m_graphsRemaining; - - if (graphsRemaining == 0 && m_isDraining) - { - m_drainSemaphore.release(); - m_isDraining = false; - } + --m_graphsRemaining; } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h index ad4c4b81c2..dc2fa5a4c8 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h @@ -76,9 +76,6 @@ namespace AZ void Submit(Internal::Task& task); - // Wait until tasks are cleared from the executor (note, does not prevent future tasks from being submitted) - // If this is used, it's expected to be used between frames to shutdown the engine - void Drain(); private: friend class Internal::TaskWorker; @@ -88,7 +85,5 @@ namespace AZ uint32_t m_threadCount = 0; AZStd::atomic m_lastSubmission; AZStd::atomic m_graphsRemaining; - AZStd::atomic m_isDraining; - AZStd::binary_semaphore m_drainSemaphore; }; } // namespace AZ diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp index eeb523ae26..f2ca484df3 100644 --- a/Code/Framework/AzCore/Tests/TaskTests.cpp +++ b/Code/Framework/AzCore/Tests/TaskTests.cpp @@ -543,95 +543,6 @@ namespace UnitTest EXPECT_EQ(3 | 0b100000, x); } - - TEST_F(TaskGraphTestFixture, ExecutorDrainRetained) - { - bool drainDone = false; - AZStd::binary_semaphore taskStart; - AZStd::binary_semaphore threadLaunched; - AZStd::binary_semaphore threadFinished; - - TaskGraph graph; - auto a = graph.AddTask( - defaultTD, - [&] - { - taskStart.acquire(); - }); - - graph.SubmitOnExecutor(*m_executor); - - AZStd::thread drainThread{ [this, &drainDone, &threadLaunched, &threadFinished] - { - threadLaunched.release(); - m_executor->Drain(); - drainDone = true; - threadFinished.release(); - } }; - - - // Wait until our drain thread has launched - threadLaunched.acquire(); - - // The task itself hasn't started, so the drain should still be blocking - EXPECT_EQ(false, drainDone); - - // Allow the task to finish - taskStart.release(); - - // Wait for the drain thread to wrap up - threadFinished.acquire(); - - // We successfully drained the executor - EXPECT_EQ(true, drainDone); - - drainThread.join(); - } - - TEST_F(TaskGraphTestFixture, ExecutorDrainDetached) - { - bool drainDone = false; - AZStd::binary_semaphore taskStart; - AZStd::binary_semaphore threadLaunched; - AZStd::binary_semaphore threadFinished; - - TaskGraph graph; - auto a = graph.AddTask( - defaultTD, - [&] - { - taskStart.acquire(); - }); - graph.Detach(); - - graph.SubmitOnExecutor(*m_executor); - - AZStd::thread drainThread{ [this, &drainDone, &threadLaunched, &threadFinished] - { - threadLaunched.release(); - m_executor->Drain(); - drainDone = true; - threadFinished.release(); - } }; - - - // Wait until our drain thread has launched - threadLaunched.acquire(); - - // The task itself hasn't started, so the drain should still be blocking - EXPECT_EQ(false, drainDone); - - // Allow the task to finish - taskStart.release(); - - // Wait for the drain thread to wrap up - threadFinished.acquire(); - - // We successfully drained the executor - EXPECT_EQ(true, drainDone); - - drainThread.join(); - } } // namespace UnitTest #if defined(HAVE_BENCHMARK) From 0f58d7394eaf8402b322663c2993062b9c23b393 Mon Sep 17 00:00:00 2001 From: greerdv Date: Fri, 6 Aug 2021 11:05:31 +0100 Subject: [PATCH 13/18] fixes #2544, fixes all doc links for physx, cloth, blast and white box Signed-off-by: greerdv --- Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp | 2 +- Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp | 2 +- Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp | 2 +- Gems/PhysX/Code/Editor/CollisionFilteringWidget.cpp | 2 +- Gems/PhysX/Code/Editor/PvdWidget.cpp | 2 +- Gems/PhysX/Code/Editor/SettingsWidget.cpp | 2 +- Gems/PhysX/Code/Source/EditorBallJointComponent.cpp | 1 + Gems/PhysX/Code/Source/EditorColliderComponent.cpp | 2 +- Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp | 1 + Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp | 2 +- Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp | 1 + Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp | 2 +- Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp | 1 + Gems/PhysX/Code/Source/NameConstants.cpp | 2 +- .../Components/EditorCharacterControllerComponent.cpp | 1 + .../Components/EditorCharacterGameplayComponent.cpp | 1 + .../Code/Source/PhysXCharacters/Components/RagdollComponent.cpp | 1 + .../Code/Source/Components/EditorWhiteBoxColliderComponent.cpp | 2 +- Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp | 2 +- 19 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp index 76a40db66e..58f28ed32a 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp @@ -38,7 +38,7 @@ namespace Blast ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute( AZ::Edit::Attributes::HelpPageURL, - "https://o3de.org/docs/user-guide/components/reference/blast-family/") + "https://o3de.org/docs/user-guide/components/reference/destruction/blast-family/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( AZ::Edit::UIHandlers::Default, &EditorBlastFamilyComponent::m_blastAsset, "Blast asset", diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp index 27e57a569e..23ec5ae524 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp @@ -61,7 +61,7 @@ namespace Blast ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute( AZ::Edit::Attributes::HelpPageURL, - "https://o3de.org/docs/user-guide/components/reference/blast-family-mesh-data/") + "https://o3de.org/docs/user-guide/components/reference/destruction/blast-family-mesh-data/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( AZ::Edit::UIHandlers::CheckBox, &EditorBlastMeshDataComponent::m_showMeshAssets, diff --git a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp index f57cc0d171..113d660b32 100644 --- a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp +++ b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp @@ -48,7 +48,7 @@ namespace NvCloth ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Cloth.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Cloth.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/cloth/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/cloth/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->UIElement(AZ::Edit::UIHandlers::CheckBox, "Simulate in editor", diff --git a/Gems/PhysX/Code/Editor/CollisionFilteringWidget.cpp b/Gems/PhysX/Code/Editor/CollisionFilteringWidget.cpp index f9de067007..4d581622ed 100644 --- a/Gems/PhysX/Code/Editor/CollisionFilteringWidget.cpp +++ b/Gems/PhysX/Code/Editor/CollisionFilteringWidget.cpp @@ -18,7 +18,7 @@ namespace PhysX namespace Editor { static const char* const s_collisionFilteringLink = "Learn more about configuring collision filtering."; - static const char* const s_collisionFilteringAddress = "configuration/collision"; + static const char* const s_collisionFilteringAddress = "configuring/configuration-collision-layers"; CollisionFilteringWidget::CollisionFilteringWidget(QWidget* parent) : QWidget(parent) diff --git a/Gems/PhysX/Code/Editor/PvdWidget.cpp b/Gems/PhysX/Code/Editor/PvdWidget.cpp index 41af8f08d8..27f1410ce5 100644 --- a/Gems/PhysX/Code/Editor/PvdWidget.cpp +++ b/Gems/PhysX/Code/Editor/PvdWidget.cpp @@ -19,7 +19,7 @@ namespace PhysX namespace Editor { static const char* const s_pvdDocumentationLink = "Learn more about the PhysX Visual Debugger (PVD)."; - static const char* const s_pvdDocumentationAddress = "configuration/debugger"; + static const char* const s_pvdDocumentationAddress = "configuring/configuration-debugger"; PvdWidget::PvdWidget(QWidget* parent) : QWidget(parent) diff --git a/Gems/PhysX/Code/Editor/SettingsWidget.cpp b/Gems/PhysX/Code/Editor/SettingsWidget.cpp index 01ee273260..39eb6ae9d8 100644 --- a/Gems/PhysX/Code/Editor/SettingsWidget.cpp +++ b/Gems/PhysX/Code/Editor/SettingsWidget.cpp @@ -19,7 +19,7 @@ namespace PhysX namespace Editor { static const char* const s_settingsDocumentationLink = "Learn more about configuring PhysX"; - static const char* const s_settingsDocumentationAddress = "configuration/global"; + static const char* const s_settingsDocumentationAddress = "configuring/configuration-global"; SettingsWidget::SettingsWidget(QWidget* parent) : QWidget(parent) diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp index 737f06a62b..d196b4644d 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp @@ -36,6 +36,7 @@ namespace PhysX ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ball-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "Limitations for the swing (Y and Z axis) about joint") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode") diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 1409760742..41db7d71ec 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -188,7 +188,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXCollider.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx-collider/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp index 24ae6dbf6a..bf5af6b78d 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp @@ -34,6 +34,7 @@ namespace PhysX ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/fixed-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) diff --git a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp index d2c6e64633..610a0a9b2e 100644 --- a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp @@ -170,7 +170,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/ForceVolume.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/ForceVolume.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx-force-region/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/force-region/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC("PhysXTriggerService", 0x3a117d7b)) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport") diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp index f82cb8bb47..6676b9865e 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp @@ -36,6 +36,7 @@ namespace PhysX ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/hinge-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "Limitations for the rotation about hinge axis") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode") diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index bd7c49a0a7..ce812a9f31 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -330,7 +330,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXRigidBody.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx-rigid-body-physics/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/rigid-body-physics/") ->DataElement(0, &EditorRigidBodyComponent::m_config, "Configuration", "Configuration for rigid body physics.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorRigidBodyComponent::CreateEditorWorldRigidBody) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 0e9a1ab8ee..7ff62e0fc6 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -85,6 +85,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXCollider.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/shape-collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderConfig, "Collider configuration", "Configuration of the collider") diff --git a/Gems/PhysX/Code/Source/NameConstants.cpp b/Gems/PhysX/Code/Source/NameConstants.cpp index 285271edf7..5f311769b8 100644 --- a/Gems/PhysX/Code/Source/NameConstants.cpp +++ b/Gems/PhysX/Code/Source/NameConstants.cpp @@ -14,7 +14,7 @@ namespace PhysX { const AZStd::string& GetPhysXDocsRoot() { - static const AZStd::string val = "https://o3de.org/docs/user-guide/interactivity/physics/"; + static const AZStd::string val = "https://o3de.org/docs/user-guide/interactivity/physics/nvidia-physx/"; return val; } } // namespace UXNameConstants diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp index d58952858d..4e24067dbf 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp @@ -99,6 +99,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXCharacter.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-controller/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_configuration, "Configuration", "Configuration for the character controller") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp index 3bc2b39ebf..81d158d81c 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp @@ -49,6 +49,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXCharacter.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-gameplay/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterGameplayComponent::m_gameplayConfig, "Gameplay Configuration", "Gameplay Configuration") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp index 844cf65707..6fa3bdbffd 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp @@ -88,6 +88,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXRagdoll.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXRagdoll.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ragdoll/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_positionIterations, "Position Iteration Count", "A higher iteration count generally improves fidelity at the cost of performance, but note that very high " diff --git a/Gems/WhiteBox/Code/Source/Components/EditorWhiteBoxColliderComponent.cpp b/Gems/WhiteBox/Code/Source/Components/EditorWhiteBoxColliderComponent.cpp index d502194126..c22be6f072 100644 --- a/Gems/WhiteBox/Code/Source/Components/EditorWhiteBoxColliderComponent.cpp +++ b/Gems/WhiteBox/Code/Source/Components/EditorWhiteBoxColliderComponent.cpp @@ -44,7 +44,7 @@ namespace WhiteBox ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute( AZ::Edit::Attributes::HelpPageURL, - "https://o3de.org/docs/user-guide/components/reference/white-box-collider/") + "https://o3de.org/docs/user-guide/components/reference/shape/white-box-collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( AZ::Edit::UIHandlers::Default, &EditorWhiteBoxColliderComponent::m_physicsColliderConfiguration, diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index 5448c5c123..ad59da63d5 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -196,7 +196,7 @@ namespace WhiteBox ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/WhiteBox.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute( - AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/white-box/") + AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/shape/white-box/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( AZ::Edit::UIHandlers::ComboBox, &EditorWhiteBoxComponent::m_defaultShape, "Default Shape", From ff8c4dce00f77d78875380ceeeb037d45bbb3b76 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Fri, 6 Aug 2021 12:50:31 +0100 Subject: [PATCH 14/18] Ensure we disconnect from EditorInteractionSystemViewportSelectionRequestBus while recreating m_interactionRequests (#2884) Fixes a crash while selecting an entity in the viewport while in 'pick' mode. --- .../EditorInteractionSystemComponent.cpp | 16 ++++++++++++---- .../ViewportUi/ViewportUiDisplay.cpp | 2 -- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 3af1672ecb..696cf6b184 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -50,11 +50,19 @@ namespace AzToolsFramework AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(GetEntityContextId()); } - m_entityDataCache = AZStd::make_unique(); + // temporarily disconnect from EditorInteractionSystemViewportSelectionRequestBus in case during the creation of + // m_interactionRequests (see interactionRequestsBuilder below) an event is propagated to the handler, if this happens then + // m_interactionRequests will be null as it will not have finished being created yet so we ensure no events are forwarded to it + EditorInteractionSystemViewportSelectionRequestBus::Handler::BusDisconnect(); - m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, - // so have to reset before assigning the new one - m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + { + m_entityDataCache = AZStd::make_unique(); + m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, + // so have to reset before assigning the new one + m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); + } + + EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId()); } void EditorInteractionSystemComponent::SetDefaultHandler() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index 3b2c26114d..80cc7941b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -380,7 +380,6 @@ namespace AzToolsFramework::ViewportUi::Internal } PrepareWidgetForViewportUi(widget); - m_renderOverlay->setFocus(); } void ViewportUiDisplay::SetUiOverlayContentsAnchored(QPointer widget, const Qt::Alignment alignment) @@ -392,7 +391,6 @@ namespace AzToolsFramework::ViewportUi::Internal PrepareWidgetForViewportUi(widget); m_uiOverlayLayout.AddAnchoredWidget(widget, alignment); - m_renderOverlay->setFocus(); } void ViewportUiDisplay::UpdateUiOverlayGeometry() From 3986a1139646d47a0ea9cdebe38eed66662dc976 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 6 Aug 2021 06:52:11 -0500 Subject: [PATCH 15/18] Fixed Asset Browser path related context menu options. Signed-off-by: Chris Galvan --- .../AzAssetBrowserRequestHandler.cpp | 14 ++-- Code/Editor/Util/FileUtil.cpp | 81 +++---------------- Code/Editor/Util/FileUtil.h | 15 +--- 3 files changed, 18 insertions(+), 92 deletions(-) diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index 50f8aff144..cb97632e07 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -260,9 +260,7 @@ void AzAssetBrowserRequestHandler::AddContextMenuActions(QWidget* caller, QMenu* return; } - AZStd::string fullFileDirectory; AZStd::string fullFilePath; - AZStd::string fileName; AZStd::string extension; switch (entry->GetEntryType()) @@ -281,8 +279,6 @@ void AzAssetBrowserRequestHandler::AddContextMenuActions(QWidget* caller, QMenu* { AZ::Uuid sourceID = azrtti_cast(entry)->GetSourceUuid(); fullFilePath = entry->GetFullPath(); - fullFileDirectory = fullFilePath.substr(0, fullFilePath.find_last_of(AZ_CORRECT_DATABASE_SEPARATOR)); - fileName = entry->GetName(); AzFramework::StringFunc::Path::GetExtension(fullFilePath.c_str(), extension); // Add the "Open" menu item. @@ -369,19 +365,19 @@ void AzAssetBrowserRequestHandler::AddContextMenuActions(QWidget* caller, QMenu* { if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source) { - CFileUtil::PopulateQMenu(caller, menu, fileName.c_str(), fullFileDirectory.c_str()); + CFileUtil::PopulateQMenu(caller, menu, fullFilePath); } return; } - CFileUtil::PopulateQMenu(caller, menu, fileName.c_str(), fullFileDirectory.c_str()); + CFileUtil::PopulateQMenu(caller, menu, fullFilePath); } break; case AssetBrowserEntry::AssetEntryType::Folder: { - fullFileDirectory = entry->GetFullPath(); - // we are sending an empty filename to indicate that it is a folder and not a file - CFileUtil::PopulateQMenu(caller, menu, fileName.c_str(), fullFileDirectory.c_str()); + fullFilePath = entry->GetFullPath(); + + CFileUtil::PopulateQMenu(caller, menu, fullFilePath); } break; default: diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index 9e4f688f69..a270a830f2 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -1900,76 +1900,25 @@ IFileUtil::ECopyTreeResult CFileUtil::MoveTree(const QString& strSourceDirecto return eCopyResult; } -QString CFileUtil::PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent) +void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath) { - QStringList extraItemsFront; - return PopupQMenu(filename, fullGamePath, parent, nullptr, extraItemsFront); + PopulateQMenu(caller, menu, fullGamePath, nullptr); } -QString CFileUtil::PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent, [[maybe_unused]] bool* pIsSelected, const QStringList& extraItemsFront) +void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath, bool* isSelected) { - QStringList extraItemsBack; - return PopupQMenu(filename, fullGamePath, parent, nullptr, extraItemsFront, extraItemsBack); -} + // Normalize the full path so we get consistent separators + AZStd::string fullFilePath(fullGamePath); + AzFramework::StringFunc::Path::Normalize(fullFilePath); -QString CFileUtil::PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent, bool* pIsSelected, const QStringList& extraItemsFront, const QStringList& extraItemsBack) -{ - QMenu menu; - - foreach(QString text, extraItemsFront) - { - if (!text.isEmpty()) - { - menu.addAction(text); - } - } - if (extraItemsFront.count()) - { - menu.addSeparator(); - } - - PopulateQMenu(parent, &menu, filename, fullGamePath, pIsSelected); - if (extraItemsBack.count()) - { - menu.addSeparator(); - } - foreach(QString text, extraItemsBack) - { - if (!text.isEmpty()) - { - menu.addAction(text); - } - } - - QAction* result = menu.exec(QCursor::pos()); - return result ? result->text() : QString(); -} - -void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const QString& filename, const QString& fullGamePath) -{ - PopulateQMenu(caller, menu, filename, fullGamePath, nullptr); -} - -void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const QString& filename, const QString& fullGamePath, bool* isSelected) -{ - QString fullPath; + QString fullPath(fullFilePath.c_str()); + QFileInfo fileInfo(fullPath); if (isSelected) { *isSelected = false; } - if (!filename.isEmpty()) - { - QString path = Path::MakeGamePath(fullGamePath); - path = Path::AddSlash(path) + filename; - fullPath = Path::GamePathToFullPath(path); - } - else - { - fullPath = fullGamePath; - } - uint32 nFileAttr = CFileUtil::GetAttributes(fullPath.toUtf8().data()); QAction* action; @@ -2005,21 +1954,13 @@ void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const QString& filen action = menu->addAction(QObject::tr("Copy Name To Clipboard"), [=]() { - if (filename.isEmpty()) - { - QFileInfo fi(fullGamePath); - QString file = fi.completeBaseName(); - QApplication::clipboard()->setText(file); - } - else - { - QApplication::clipboard()->setText(filename); - } + QString fileName = fileInfo.completeBaseName(); + QApplication::clipboard()->setText(fileName); }); action = menu->addAction(QObject::tr("Copy Path To Clipboard"), [fullPath]() { QApplication::clipboard()->setText(fullPath); }); - if (!filename.isEmpty() && GetIEditor()->IsSourceControlAvailable() && nFileAttr != SCC_FILE_ATTRIBUTE_INVALID) + if (fileInfo.isFile() && GetIEditor()->IsSourceControlAvailable() && nFileAttr != SCC_FILE_ATTRIBUTE_INVALID) { bool isEnableSC = nFileAttr & SCC_FILE_ATTRIBUTE_MANAGED; bool isInPak = nFileAttr & SCC_FILE_ATTRIBUTE_INPAK; diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 000215e98d..599e0f0b2a 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -134,18 +134,7 @@ public: // THIS FUNCTION IS NOT DESIGNED FOR MULTI-THREADED USAGE static IFileUtil::ECopyTreeResult MoveTree(const QString& strSourceDirectory, const QString& strTargetDirectory, bool boRecurse = true, bool boConfirmOverwrite = false); - // Show Popup Menu with file commands include Source Control commands - // filename: a name of file without path - // fullGamePath: a game path to folder like "/Game/Objects" without filename - // wnd: pointer to window class, can be nullptr - // isSelected: output value indicated if Select menu item was chosen, if pointer is 0 - no Select menu item. - // pItems: you can specify additional menu items and get the result of selection using this parameter. - // return false if source control operation failed - static QString PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent); - static QString PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent, bool* pIsSelected, const QStringList& extraItemsFront); - static QString PopupQMenu(const QString& filename, const QString& fullGamePath, QWidget* parent, bool* pIsSelected, const QStringList& extraItemsFront, const QStringList& extraItemsBack); - - static void PopulateQMenu(QWidget* caller, QMenu* menu, const QString& filename, const QString& fullGamePath); + static void PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath); static void GatherAssetFilenamesFromLevel(std::set& rOutFilenames, bool bMakeLowerCase = false, bool bMakeUnixPath = false); @@ -172,7 +161,7 @@ private: static bool s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST]; // Keep this variant of this method private! pIsSelected is captured in a lambda, and so requires menu use exec() and never use show() - static void PopulateQMenu(QWidget* caller, QMenu* menu, const QString& filename, const QString& fullGamePath, bool* pIsSelected); + static void PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath, bool* pIsSelected); static bool ExtractDccFilenameFromAssetDatabase(const QString& assetFilename, QString& dccFilename); static bool ExtractDccFilenameUsingNamingConventions(const QString& assetFilename, QString& dccFilename); From eeb1b68a725112dc0ac0598e14ed32be404eed66 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 6 Aug 2021 09:23:33 -0500 Subject: [PATCH 16/18] Updated string to string_view per PR feedback. Signed-off-by: Chris Galvan --- Code/Editor/Util/FileUtil.cpp | 4 ++-- Code/Editor/Util/FileUtil.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index a270a830f2..5356e4abc2 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -1900,12 +1900,12 @@ IFileUtil::ECopyTreeResult CFileUtil::MoveTree(const QString& strSourceDirecto return eCopyResult; } -void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath) +void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, AZStd::string_view fullGamePath) { PopulateQMenu(caller, menu, fullGamePath, nullptr); } -void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath, bool* isSelected) +void CFileUtil::PopulateQMenu(QWidget* caller, QMenu* menu, AZStd::string_view fullGamePath, bool* isSelected) { // Normalize the full path so we get consistent separators AZStd::string fullFilePath(fullGamePath); diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 599e0f0b2a..1d907e5baf 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -134,7 +134,7 @@ public: // THIS FUNCTION IS NOT DESIGNED FOR MULTI-THREADED USAGE static IFileUtil::ECopyTreeResult MoveTree(const QString& strSourceDirectory, const QString& strTargetDirectory, bool boRecurse = true, bool boConfirmOverwrite = false); - static void PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath); + static void PopulateQMenu(QWidget* caller, QMenu* menu, AZStd::string_view fullGamePath); static void GatherAssetFilenamesFromLevel(std::set& rOutFilenames, bool bMakeLowerCase = false, bool bMakeUnixPath = false); @@ -161,7 +161,7 @@ private: static bool s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST]; // Keep this variant of this method private! pIsSelected is captured in a lambda, and so requires menu use exec() and never use show() - static void PopulateQMenu(QWidget* caller, QMenu* menu, const AZStd::string& fullGamePath, bool* pIsSelected); + static void PopulateQMenu(QWidget* caller, QMenu* menu, AZStd::string_view fullGamePath, bool* pIsSelected); static bool ExtractDccFilenameFromAssetDatabase(const QString& assetFilename, QString& dccFilename); static bool ExtractDccFilenameUsingNamingConventions(const QString& assetFilename, QString& dccFilename); From 2c7f6f9742f705129db68445f8ed6dc4c5681440 Mon Sep 17 00:00:00 2001 From: AMZN-nggieber <52797929+AMZN-nggieber@users.noreply.github.com> Date: Fri, 6 Aug 2021 08:19:35 -0700 Subject: [PATCH 17/18] Adds Links to Gem Directory and Documentation for Gems (#2922) * Changed blue text to white that is not meant as a link, made 'View in Director' link work for gems in the inspector, added parsing for gem documentation link Signed-off-by: nggieber * Added documentation links for gems, changed markup for urls in summaries and requirements so they are clickable Signed-off-by: nggieber * Fixed a couple of the documentation links Signed-off-by: nggieber * Added documentation url to edit gem properties script and updated unit tests Signed-off-by: nggieber --- .../Source/GemCatalog/GemInspector.cpp | 6 ++++- .../Source/GemCatalog/GemInspector.h | 1 - .../Source/GemCatalog/GemItemDelegate.cpp | 1 - .../ProjectManager/Source/PythonBindings.cpp | 2 ++ Gems/AWSClientAuth/gem.json | 3 ++- Gems/AWSCore/gem.json | 3 ++- Gems/AWSGameLift/gem.json | 3 ++- Gems/AWSMetrics/gem.json | 3 ++- Gems/Achievements/gem.json | 3 ++- Gems/AssetMemoryAnalyzer/gem.json | 3 ++- Gems/AssetValidation/gem.json | 3 ++- Gems/Atom/gem.json | 3 ++- Gems/AtomContent/gem.json | 5 ++-- Gems/AtomLyIntegration/gem.json | 3 ++- Gems/AtomTressFX/gem.json | 3 ++- Gems/AudioEngineWwise/gem.json | 3 ++- Gems/AudioSystem/gem.json | 3 ++- Gems/Blast/gem.json | 3 ++- Gems/Camera/gem.json | 3 ++- Gems/CameraFramework/gem.json | 3 ++- Gems/CertificateManager/gem.json | 3 ++- Gems/CrashReporting/gem.json | 3 ++- Gems/CustomAssetExample/gem.json | 3 ++- Gems/DebugDraw/gem.json | 3 ++- Gems/DevTextures/gem.json | 3 ++- Gems/EMotionFX/gem.json | 3 ++- Gems/EditorPythonBindings/gem.json | 21 +++++++++-------- Gems/ExpressionEvaluation/gem.json | 3 ++- Gems/FastNoise/gem.json | 3 ++- Gems/GameState/gem.json | 3 ++- Gems/GameStateSamples/gem.json | 3 ++- Gems/Gestures/gem.json | 3 ++- Gems/GradientSignal/gem.json | 3 ++- Gems/GraphCanvas/gem.json | 3 ++- Gems/GraphModel/gem.json | 3 ++- Gems/HttpRequestor/gem.json | 3 ++- Gems/ImGui/gem.json | 3 ++- Gems/InAppPurchases/gem.json | 3 ++- Gems/LandscapeCanvas/gem.json | 3 ++- Gems/LmbrCentral/gem.json | 3 ++- Gems/LocalUser/gem.json | 3 ++- Gems/LyShine/gem.json | 3 ++- Gems/LyShineExamples/gem.json | 3 ++- Gems/Maestro/gem.json | 3 ++- Gems/MessagePopup/gem.json | 3 ++- Gems/Metastream/gem.json | 3 ++- Gems/Microphone/gem.json | 3 ++- Gems/MultiplayerCompression/gem.json | 3 ++- Gems/NvCloth/gem.json | 3 ++- Gems/PBSreferenceMaterials/gem.json | 3 ++- Gems/PhysX/gem.json | 3 ++- Gems/PhysXDebug/gem.json | 3 ++- Gems/PhysXSamples/gem.json | 3 ++- Gems/Prefab/PrefabBuilder/gem.json | 3 ++- Gems/Presence/gem.json | 3 ++- Gems/PrimitiveAssets/gem.json | 3 ++- Gems/PythonAssetBuilder/gem.json | 21 +++++++++-------- Gems/QtForPython/gem.json | 5 ++-- Gems/RADTelemetry/gem.json | 3 ++- Gems/SaveData/gem.json | 5 ++-- Gems/SceneLoggingExample/gem.json | 5 ++-- Gems/SceneProcessing/gem.json | 5 ++-- Gems/ScriptCanvas/gem.json | 21 +++++++++-------- Gems/ScriptCanvasDeveloper/gem.json | 5 ++-- Gems/ScriptCanvasPhysics/gem.json | 5 ++-- Gems/ScriptCanvasTesting/gem.json | 21 +++++++++-------- Gems/ScriptEvents/gem.json | 21 +++++++++-------- Gems/ScriptedEntityTweener/gem.json | 5 ++-- Gems/StartingPointCamera/gem.json | 3 ++- Gems/StartingPointInput/gem.json | 3 ++- Gems/StartingPointMovement/gem.json | 3 ++- Gems/SurfaceData/gem.json | 3 ++- Gems/TestAssetBuilder/gem.json | 3 ++- Gems/TextureAtlas/gem.json | 3 ++- Gems/TickBusOrderViewer/gem.json | 3 ++- Gems/Twitch/gem.json | 3 ++- Gems/UiBasics/gem.json | 3 ++- Gems/Vegetation/gem.json | 3 ++- Gems/VideoPlaybackFramework/gem.json | 3 ++- Gems/VirtualGamepad/gem.json | 3 ++- Gems/WhiteBox/gem.json | 3 ++- scripts/o3de/o3de/gem_properties.py | 18 ++++++++++----- .../o3de/tests/unit_test_gem_properties.py | 23 +++++++++++-------- 83 files changed, 240 insertions(+), 148 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index ec4a80e175..6c1f5f6fec 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -108,7 +108,7 @@ namespace O3DE::ProjectManager { // Gem name, creator and summary m_nameLabel = CreateStyledLabel(m_mainLayout, 18, s_headerColor); - m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_creatorColor); + m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_headerColor); m_mainLayout->addSpacing(5); // TODO: QLabel seems to have issues determining the right sizeHint() for our font with the given font size. @@ -116,6 +116,8 @@ namespace O3DE::ProjectManager m_summaryLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); m_mainLayout->addWidget(m_summaryLabel); m_summaryLabel->setWordWrap(true); + m_summaryLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_summaryLabel->setOpenExternalLinks(true); m_mainLayout->addSpacing(5); // Directory and documentation links @@ -161,6 +163,8 @@ namespace O3DE::ProjectManager m_reqirementsTextLabel = GemInspector::CreateStyledLabel(requrementsLayout, 10, s_textColor); m_reqirementsTextLabel->setWordWrap(true); + m_reqirementsTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_reqirementsTextLabel->setOpenExternalLinks(true); QSpacerItem* reqirementsSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding); requrementsLayout->addSpacerItem(reqirementsSpacer); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h index 7d80cb0905..97c23f7df2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h @@ -38,7 +38,6 @@ namespace O3DE::ProjectManager // Colors inline constexpr static const char* s_headerColor = "#FFFFFF"; inline constexpr static const char* s_textColor = "#DDDDDD"; - inline constexpr static const char* s_creatorColor = "#94D2FF"; private slots: void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 8f5cfd24aa..d5a213e80f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -95,7 +95,6 @@ namespace O3DE::ProjectManager gemCreatorRect.moveTo(contentRect.left(), contentRect.top() + gemNameRect.height()); painter->setFont(standardFont); - painter->setPen(m_linkColor); gemCreatorRect = painter->boundingRect(gemCreatorRect, Qt::TextSingleLine, gemCreator); painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 5d118654bc..8bdfb0f152 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -646,6 +646,7 @@ namespace O3DE::ProjectManager { GemInfo gemInfo; gemInfo.m_path = Py_To_String(path); + gemInfo.m_directoryLink = gemInfo.m_path; auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path, pyProjectPath); if (pybind11::isinstance(data)) @@ -661,6 +662,7 @@ namespace O3DE::ProjectManager gemInfo.m_version = ""; gemInfo.m_requirement = Py_To_String_Optional(data, "requirements", ""); gemInfo.m_creator = Py_To_String_Optional(data, "origin", ""); + gemInfo.m_documentationLink = Py_To_String_Optional(data, "documentation_url", ""); if (gemInfo.m_creator.contains("Open 3D Engine")) { diff --git a/Gems/AWSClientAuth/gem.json b/Gems/AWSClientAuth/gem.json index 76183cd785..42996e7f4f 100644 --- a/Gems/AWSClientAuth/gem.json +++ b/Gems/AWSClientAuth/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["AWS", "Network", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/" } diff --git a/Gems/AWSCore/gem.json b/Gems/AWSCore/gem.json index bbaa4eb155..4c7889ace4 100644 --- a/Gems/AWSCore/gem.json +++ b/Gems/AWSCore/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["AWS", "Network", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-core/" } diff --git a/Gems/AWSGameLift/gem.json b/Gems/AWSGameLift/gem.json index 1a19c82f0b..7711495ee7 100644 --- a/Gems/AWSGameLift/gem.json +++ b/Gems/AWSGameLift/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["AWS", "Framework", "Network"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-gamelift/" } diff --git a/Gems/AWSMetrics/gem.json b/Gems/AWSMetrics/gem.json index 480200c565..5faeb66787 100644 --- a/Gems/AWSMetrics/gem.json +++ b/Gems/AWSMetrics/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["AWS", "Network", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/" } diff --git a/Gems/Achievements/gem.json b/Gems/Achievements/gem.json index 8a30390295..ca2bc7f3e9 100644 --- a/Gems/Achievements/gem.json +++ b/Gems/Achievements/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Achievements"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/gameplay/achievements/" } diff --git a/Gems/AssetMemoryAnalyzer/gem.json b/Gems/AssetMemoryAnalyzer/gem.json index 45610e417c..544e0f7948 100644 --- a/Gems/AssetMemoryAnalyzer/gem.json +++ b/Gems/AssetMemoryAnalyzer/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "Utility", "Tools"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/debug/asset-memory-analyzer/" } diff --git a/Gems/AssetValidation/gem.json b/Gems/AssetValidation/gem.json index 8a00dc27ca..83e37ddaf5 100644 --- a/Gems/AssetValidation/gem.json +++ b/Gems/AssetValidation/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Utility", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/asset-validation/" } diff --git a/Gems/Atom/gem.json b/Gems/Atom/gem.json index c2aa033bf7..f927e42e7e 100644 --- a/Gems/Atom/gem.json +++ b/Gems/Atom/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Core"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/atom/atom/" } diff --git a/Gems/AtomContent/gem.json b/Gems/AtomContent/gem.json index b1bc35b77b..8161635f43 100644 --- a/Gems/AtomContent/gem.json +++ b/Gems/AtomContent/gem.json @@ -4,9 +4,10 @@ "license": "Apache-2.0 Or MIT", "origin": "Open 3D Engine - o3de.org", "type": "Asset", - "summary": "The Atom Content Gem provides assets for Atom Renderer and a modified version of the Pixar Look Development Studio (https://renderman.pixar.com/look-development-studio).", + "summary": "The Atom Content Gem provides assets for Atom Renderer and a modified version of the Pixar Look Development Studio.", "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Assets", "Tools"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/atom/atom-content/" } diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json index 72be2f9151..28faf364db 100644 --- a/Gems/AtomLyIntegration/gem.json +++ b/Gems/AtomLyIntegration/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Core", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/atom/atom-ly-integration/" } diff --git a/Gems/AtomTressFX/gem.json b/Gems/AtomTressFX/gem.json index 0099906dd1..5f2e25b8a9 100644 --- a/Gems/AtomTressFX/gem.json +++ b/Gems/AtomTressFX/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Physics", "Animation"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/amd/atom-tressfx/" } diff --git a/Gems/AudioEngineWwise/gem.json b/Gems/AudioEngineWwise/gem.json index 699ed8419a..084c924977 100644 --- a/Gems/AudioEngineWwise/gem.json +++ b/Gems/AudioEngineWwise/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Audio", "Utility", "Tools"], "icon_path": "preview.png", - "requirements": "Users will need to download Wwise from the Audiokinetic web site: https://www.audiokinetic.com/download/" + "requirements": "Users will need to download Wwise from the Audiokinetic Web Site.", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/audio/wwise/audio-engine-wwise/" } diff --git a/Gems/AudioSystem/gem.json b/Gems/AudioSystem/gem.json index a9058cb42e..f618103803 100644 --- a/Gems/AudioSystem/gem.json +++ b/Gems/AudioSystem/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Audio", "Utility", "Tools"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/audio/audio-system/" } diff --git a/Gems/Blast/gem.json b/Gems/Blast/gem.json index a4eb9d6b31..3b1205d6fe 100644 --- a/Gems/Blast/gem.json +++ b/Gems/Blast/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Physics", "Simulation", "Animation"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/physics/nvidia/nvidia-blast/" } diff --git a/Gems/Camera/gem.json b/Gems/Camera/gem.json index f59bb8cc0d..2fc2ea8355 100644 --- a/Gems/Camera/gem.json +++ b/Gems/Camera/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/camera/" } diff --git a/Gems/CameraFramework/gem.json b/Gems/CameraFramework/gem.json index 6a6cbaf1f0..2ab25a84b4 100644 --- a/Gems/CameraFramework/gem.json +++ b/Gems/CameraFramework/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Framework", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/camera-framework/" } diff --git a/Gems/CertificateManager/gem.json b/Gems/CertificateManager/gem.json index 38005a7cd1..cb49abc6b6 100644 --- a/Gems/CertificateManager/gem.json +++ b/Gems/CertificateManager/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Network", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/network/certificate-manager/" } diff --git a/Gems/CrashReporting/gem.json b/Gems/CrashReporting/gem.json index e1e06f0ac1..bff54dcf36 100644 --- a/Gems/CrashReporting/gem.json +++ b/Gems/CrashReporting/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/debug/crash-reporting/" } diff --git a/Gems/CustomAssetExample/gem.json b/Gems/CustomAssetExample/gem.json index 62bdcb1ff6..ac7c2788d7 100644 --- a/Gems/CustomAssetExample/gem.json +++ b/Gems/CustomAssetExample/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Tools"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/custom-asset-example/" } diff --git a/Gems/DebugDraw/gem.json b/Gems/DebugDraw/gem.json index 0dd2e179f3..a7939f4077 100644 --- a/Gems/DebugDraw/gem.json +++ b/Gems/DebugDraw/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "Tools", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/debug/debug-draw/" } diff --git a/Gems/DevTextures/gem.json b/Gems/DevTextures/gem.json index 7a27d7c776..81d14e78cb 100644 --- a/Gems/DevTextures/gem.json +++ b/Gems/DevTextures/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Debug", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/dev-textures/" } diff --git a/Gems/EMotionFX/gem.json b/Gems/EMotionFX/gem.json index 74a060ed52..f00803ec2c 100644 --- a/Gems/EMotionFX/gem.json +++ b/Gems/EMotionFX/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Animation", "Tools", "Simulation"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/animation/emotionfx/" } diff --git a/Gems/EditorPythonBindings/gem.json b/Gems/EditorPythonBindings/gem.json index a8ae59b22e..fae091a63f 100644 --- a/Gems/EditorPythonBindings/gem.json +++ b/Gems/EditorPythonBindings/gem.json @@ -1,12 +1,13 @@ { - "gem_name": "EditorPythonBindings", - "display_name": "Editor Python Bindings", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Tool", - "summary": "The Editor Python Bindings Gem provides Python commands for Open 3D Engine Editor functions.", - "canonical_tags": ["Gem"], - "user_tags": ["Scripting", "Utility"], - "icon_path": "preview.png", - "requirements": "" + "gem_name": "EditorPythonBindings", + "display_name": "Editor Python Bindings", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "type": "Tool", + "summary": "The Editor Python Bindings Gem provides Python commands for Open 3D Engine Editor functions.", + "canonical_tags": ["Gem"], + "user_tags": ["Scripting", "Utility"], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/python/editor-python-bindings/" } diff --git a/Gems/ExpressionEvaluation/gem.json b/Gems/ExpressionEvaluation/gem.json index 92d5963891..2f555916a5 100644 --- a/Gems/ExpressionEvaluation/gem.json +++ b/Gems/ExpressionEvaluation/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Scripting", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/expression-evaluation/" } diff --git a/Gems/FastNoise/gem.json b/Gems/FastNoise/gem.json index f49db2aa02..5ee5bbaf89 100644 --- a/Gems/FastNoise/gem.json +++ b/Gems/FastNoise/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Utility", "Tools", "Design"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/utility/fast-noise/" } diff --git a/Gems/GameState/gem.json b/Gems/GameState/gem.json index fe9569eb75..a1f272c290 100644 --- a/Gems/GameState/gem.json +++ b/Gems/GameState/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Framework", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/gameplay/game-state/" } diff --git a/Gems/GameStateSamples/gem.json b/Gems/GameStateSamples/gem.json index 0241a8a1b7..f0dd82c5fa 100644 --- a/Gems/GameStateSamples/gem.json +++ b/Gems/GameStateSamples/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Sample", "Assets"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/gameplay/game-state-samples/" } diff --git a/Gems/Gestures/gem.json b/Gems/Gestures/gem.json index 4c2f5fe67a..4412e58c6d 100644 --- a/Gems/Gestures/gem.json +++ b/Gems/Gestures/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Input", "Gameplay", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/input/gestures/" } diff --git a/Gems/GradientSignal/gem.json b/Gems/GradientSignal/gem.json index cae1a272b1..67afb1f819 100644 --- a/Gems/GradientSignal/gem.json +++ b/Gems/GradientSignal/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Utility", "Tools", "Design"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/utility/gradient-signal/" } diff --git a/Gems/GraphCanvas/gem.json b/Gems/GraphCanvas/gem.json index 6884f6b9cb..ab1e7ac77a 100644 --- a/Gems/GraphCanvas/gem.json +++ b/Gems/GraphCanvas/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Framework", "Tools", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/framework/graph-canvas/" } diff --git a/Gems/GraphModel/gem.json b/Gems/GraphModel/gem.json index 52c914357d..62f1effb7c 100644 --- a/Gems/GraphModel/gem.json +++ b/Gems/GraphModel/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Framework", "Tools", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/framework/graph-model/" } diff --git a/Gems/HttpRequestor/gem.json b/Gems/HttpRequestor/gem.json index 8beb77d839..e5eb8d6f44 100644 --- a/Gems/HttpRequestor/gem.json +++ b/Gems/HttpRequestor/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Network", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/network/http-requestor/" } diff --git a/Gems/ImGui/gem.json b/Gems/ImGui/gem.json index 327e417bcf..deaac9925a 100644 --- a/Gems/ImGui/gem.json +++ b/Gems/ImGui/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "Rendering", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/debug/imgui/" } diff --git a/Gems/InAppPurchases/gem.json b/Gems/InAppPurchases/gem.json index 96d0e7fa0a..ab43075896 100644 --- a/Gems/InAppPurchases/gem.json +++ b/Gems/InAppPurchases/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["SDK", "Network"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/sdk/in-app-purchases/" } diff --git a/Gems/LandscapeCanvas/gem.json b/Gems/LandscapeCanvas/gem.json index 338845ebb1..63a80ec57e 100644 --- a/Gems/LandscapeCanvas/gem.json +++ b/Gems/LandscapeCanvas/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Environment", "Design", "Tools"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/environment/landscape-canvas/" } diff --git a/Gems/LmbrCentral/gem.json b/Gems/LmbrCentral/gem.json index 6f0530c35d..b6442bfd06 100644 --- a/Gems/LmbrCentral/gem.json +++ b/Gems/LmbrCentral/gem.json @@ -8,6 +8,7 @@ "canonical_tags": ["Gem"], "user_tags": ["Core", "Framework", "Assets"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/core/lmbr-central/" } diff --git a/Gems/LocalUser/gem.json b/Gems/LocalUser/gem.json index 47c1601240..dcf4d44abb 100644 --- a/Gems/LocalUser/gem.json +++ b/Gems/LocalUser/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Input", "Gameplay", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/input/local-user/" } diff --git a/Gems/LyShine/gem.json b/Gems/LyShine/gem.json index c61ca0cce5..e0fdb860e5 100644 --- a/Gems/LyShine/gem.json +++ b/Gems/LyShine/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["UI", "Tools", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/ui/lyshine/" } diff --git a/Gems/LyShineExamples/gem.json b/Gems/LyShineExamples/gem.json index e8c7110466..a411bfb363 100644 --- a/Gems/LyShineExamples/gem.json +++ b/Gems/LyShineExamples/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["UI", "Sample", "Assets"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/ui/lyshine-examples/" } diff --git a/Gems/Maestro/gem.json b/Gems/Maestro/gem.json index 4f638b63f1..6ee989aa55 100644 --- a/Gems/Maestro/gem.json +++ b/Gems/Maestro/gem.json @@ -8,6 +8,7 @@ "canonical_tags": ["Gem"], "user_tags": ["Animation", "Tools", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/animation/maestro/" } diff --git a/Gems/MessagePopup/gem.json b/Gems/MessagePopup/gem.json index c75d28f50d..2560b8869a 100644 --- a/Gems/MessagePopup/gem.json +++ b/Gems/MessagePopup/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Sample"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/ui/message-popup/" } diff --git a/Gems/Metastream/gem.json b/Gems/Metastream/gem.json index 911c6be665..429d174cf5 100644 --- a/Gems/Metastream/gem.json +++ b/Gems/Metastream/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Network", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/network/twitch/metastream/" } diff --git a/Gems/Microphone/gem.json b/Gems/Microphone/gem.json index 31b3d46963..cc47cbcd7e 100644 --- a/Gems/Microphone/gem.json +++ b/Gems/Microphone/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Audio", "Input"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/audio/microphone/" } diff --git a/Gems/MultiplayerCompression/gem.json b/Gems/MultiplayerCompression/gem.json index aeea2282cc..178cca0ffe 100644 --- a/Gems/MultiplayerCompression/gem.json +++ b/Gems/MultiplayerCompression/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Multiplayer", "Network", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/multiplayer/multiplayer-compression/" } diff --git a/Gems/NvCloth/gem.json b/Gems/NvCloth/gem.json index 95ea8168d6..49ccbf32f1 100644 --- a/Gems/NvCloth/gem.json +++ b/Gems/NvCloth/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Physics", "Simulation", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/physics/nvidia/nvidia-cloth/" } diff --git a/Gems/PBSreferenceMaterials/gem.json b/Gems/PBSreferenceMaterials/gem.json index b015d89888..563dd31a38 100644 --- a/Gems/PBSreferenceMaterials/gem.json +++ b/Gems/PBSreferenceMaterials/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Sample", "Assets"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/pbs-reference-materials/" } diff --git a/Gems/PhysX/gem.json b/Gems/PhysX/gem.json index 0b6b635c71..0fbd3e44f9 100644 --- a/Gems/PhysX/gem.json +++ b/Gems/PhysX/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Physics", "Simulation", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/physics/nvidia/physx/" } diff --git a/Gems/PhysXDebug/gem.json b/Gems/PhysXDebug/gem.json index 7dbfc1a096..f7877cabdd 100644 --- a/Gems/PhysXDebug/gem.json +++ b/Gems/PhysXDebug/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Physics", "Simulation", "Debug"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/physics/nvidia/physx-debug/" } diff --git a/Gems/PhysXSamples/gem.json b/Gems/PhysXSamples/gem.json index b5239344f6..e48dc6991b 100644 --- a/Gems/PhysXSamples/gem.json +++ b/Gems/PhysXSamples/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Physics", "Simulation", "Sample"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/physics/nvidia/physx-samples/" } diff --git a/Gems/Prefab/PrefabBuilder/gem.json b/Gems/Prefab/PrefabBuilder/gem.json index 1a815738ca..ad6062ae3b 100644 --- a/Gems/Prefab/PrefabBuilder/gem.json +++ b/Gems/Prefab/PrefabBuilder/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Utility", "Core"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/prefab/" } diff --git a/Gems/Presence/gem.json b/Gems/Presence/gem.json index 5df5fbdd6a..49d937946d 100644 --- a/Gems/Presence/gem.json +++ b/Gems/Presence/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Network", "Gameplay", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/network/presence/" } diff --git a/Gems/PrimitiveAssets/gem.json b/Gems/PrimitiveAssets/gem.json index 1c1fd54c16..d1789d46fe 100644 --- a/Gems/PrimitiveAssets/gem.json +++ b/Gems/PrimitiveAssets/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Sample", "Debug"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/primitive-assets/" } diff --git a/Gems/PythonAssetBuilder/gem.json b/Gems/PythonAssetBuilder/gem.json index dcf3b59e23..1a76d7d2c2 100644 --- a/Gems/PythonAssetBuilder/gem.json +++ b/Gems/PythonAssetBuilder/gem.json @@ -1,12 +1,13 @@ { - "gem_name": "PythonAssetBuilder", - "display_name": "Python Asset Builder", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Code", - "summary": "The Python Asset Builder Gem provides functionality to implement custom asset builders in Python for Asset Processor.", - "canonical_tags": ["Gem"], - "user_tags": ["Scripting", "Assets", "Utility"], - "icon_path": "preview.png", - "requirements": "" + "gem_name": "PythonAssetBuilder", + "display_name": "Python Asset Builder", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "type": "Code", + "summary": "The Python Asset Builder Gem provides functionality to implement custom asset builders in Python for Asset Processor.", + "canonical_tags": ["Gem"], + "user_tags": ["Scripting", "Assets", "Utility"], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/python/python-asset-builder/" } diff --git a/Gems/QtForPython/gem.json b/Gems/QtForPython/gem.json index dea5fc2e16..1519d46c52 100644 --- a/Gems/QtForPython/gem.json +++ b/Gems/QtForPython/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Scripting", "UI", "Framework"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/python/qt-for-python/" +} diff --git a/Gems/RADTelemetry/gem.json b/Gems/RADTelemetry/gem.json index 43515976da..932093b4a9 100644 --- a/Gems/RADTelemetry/gem.json +++ b/Gems/RADTelemetry/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "SDK"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/debug/rad/rad-telemetry/" } diff --git a/Gems/SaveData/gem.json b/Gems/SaveData/gem.json index 57de27624f..3892cc80c2 100644 --- a/Gems/SaveData/gem.json +++ b/Gems/SaveData/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Utility", "Gameplay"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/utility/save-data/" +} diff --git a/Gems/SceneLoggingExample/gem.json b/Gems/SceneLoggingExample/gem.json index faa2860d13..ff7def1b32 100644 --- a/Gems/SceneLoggingExample/gem.json +++ b/Gems/SceneLoggingExample/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Debug", "Sample"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/utility/scene-logging-example/" +} diff --git a/Gems/SceneProcessing/gem.json b/Gems/SceneProcessing/gem.json index d9814f6a7d..a6c2cefbd6 100644 --- a/Gems/SceneProcessing/gem.json +++ b/Gems/SceneProcessing/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Tools", "Core"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/scene-processing/" +} diff --git a/Gems/ScriptCanvas/gem.json b/Gems/ScriptCanvas/gem.json index 413e58ef7e..b6b5522d7d 100644 --- a/Gems/ScriptCanvas/gem.json +++ b/Gems/ScriptCanvas/gem.json @@ -1,12 +1,13 @@ { - "gem_name": "ScriptCanvas", - "display_name": "Script Canvas", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Tool", - "summary": "The Script Canvas Gem provides Open 3D Engine's visual scripting environment, Script Canvas.", - "canonical_tags": ["Gem"], - "user_tags": ["Scripting", "Tools", "Utility"], - "icon_path": "preview.png", - "requirements": "" + "gem_name": "ScriptCanvas", + "display_name": "Script Canvas", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "type": "Tool", + "summary": "The Script Canvas Gem provides Open 3D Engine's visual scripting environment, Script Canvas.", + "canonical_tags": ["Gem"], + "user_tags": ["Scripting", "Tools", "Utility"], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/script-canvas/" } diff --git a/Gems/ScriptCanvasDeveloper/gem.json b/Gems/ScriptCanvasDeveloper/gem.json index 7cc2e7d03a..d7b0aefad3 100644 --- a/Gems/ScriptCanvasDeveloper/gem.json +++ b/Gems/ScriptCanvasDeveloper/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Scripting", "Utility", "Debug"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/script-canvas-developer/" +} diff --git a/Gems/ScriptCanvasPhysics/gem.json b/Gems/ScriptCanvasPhysics/gem.json index 04cfb86980..46e2ef1194 100644 --- a/Gems/ScriptCanvasPhysics/gem.json +++ b/Gems/ScriptCanvasPhysics/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Scripting", "Physics", "Simulation"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/script-canvas-physics/" +} diff --git a/Gems/ScriptCanvasTesting/gem.json b/Gems/ScriptCanvasTesting/gem.json index d82e841236..303eab8c7e 100644 --- a/Gems/ScriptCanvasTesting/gem.json +++ b/Gems/ScriptCanvasTesting/gem.json @@ -1,12 +1,13 @@ { - "gem_name": "ScriptCanvasTesting", - "display_name": "Script Canvas Testing", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Tool", - "summary": "The Script Canvas Testing Gem provides a framework for testing for and with Script Canvas.", - "canonical_tags": ["Gem"], - "user_tags": ["Scripting", "Debug", "Framework"], - "icon_path": "preview.png", - "requirements": "" + "gem_name": "ScriptCanvasTesting", + "display_name": "Script Canvas Testing", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "type": "Tool", + "summary": "The Script Canvas Testing Gem provides a framework for testing for and with Script Canvas.", + "canonical_tags": ["Gem"], + "user_tags": ["Scripting", "Debug", "Framework"], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/script-canvas-testing/" } diff --git a/Gems/ScriptEvents/gem.json b/Gems/ScriptEvents/gem.json index fba99c6af9..2b7d74ef3f 100644 --- a/Gems/ScriptEvents/gem.json +++ b/Gems/ScriptEvents/gem.json @@ -1,12 +1,13 @@ { - "gem_name": "ScriptEvents", - "display_name": "Script Events", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Code", - "summary": "The Script Events Gem provides a framework for creating event assets usable from any scripting solution in Open 3D Engine.", - "canonical_tags": ["Gem"], - "user_tags": ["Scripting", "Framework", "Gameplay"], - "icon_path": "preview.png", - "requirements": "" + "gem_name": "ScriptEvents", + "display_name": "Script Events", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "type": "Code", + "summary": "The Script Events Gem provides a framework for creating event assets usable from any scripting solution in Open 3D Engine.", + "canonical_tags": ["Gem"], + "user_tags": ["Scripting", "Framework", "Gameplay"], + "icon_path": "preview.png", + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/script-events/" } diff --git a/Gems/ScriptedEntityTweener/gem.json b/Gems/ScriptedEntityTweener/gem.json index c2e1975f76..a0f558356b 100644 --- a/Gems/ScriptedEntityTweener/gem.json +++ b/Gems/ScriptedEntityTweener/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Scripting", "UI", "Animation"], "icon_path": "preview.png", - "requirements": "" - } + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/script/scripted-entity-tweener/" +} diff --git a/Gems/StartingPointCamera/gem.json b/Gems/StartingPointCamera/gem.json index 2c28f346a9..5a9aa0df9b 100644 --- a/Gems/StartingPointCamera/gem.json +++ b/Gems/StartingPointCamera/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Gameplay", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/starting-point-camera/" } diff --git a/Gems/StartingPointInput/gem.json b/Gems/StartingPointInput/gem.json index 2d5b6aee15..e65f271fe5 100644 --- a/Gems/StartingPointInput/gem.json +++ b/Gems/StartingPointInput/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Input", "Gameplay", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/input/starting-point-input/" } diff --git a/Gems/StartingPointMovement/gem.json b/Gems/StartingPointMovement/gem.json index cb4e8d0e6a..70e1d105c1 100644 --- a/Gems/StartingPointMovement/gem.json +++ b/Gems/StartingPointMovement/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Input", "Gameplay", "Scripting"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/input/starting-point-movement/" } diff --git a/Gems/SurfaceData/gem.json b/Gems/SurfaceData/gem.json index 24f7f1cb21..57e4d8fb70 100644 --- a/Gems/SurfaceData/gem.json +++ b/Gems/SurfaceData/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Environment", "Utility", "Design"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/environment/surface-data/" } diff --git a/Gems/TestAssetBuilder/gem.json b/Gems/TestAssetBuilder/gem.json index 4c75343ebb..1e0b84894a 100644 --- a/Gems/TestAssetBuilder/gem.json +++ b/Gems/TestAssetBuilder/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Assets", "Debug", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/assets/test-asset-builder/" } diff --git a/Gems/TextureAtlas/gem.json b/Gems/TextureAtlas/gem.json index 1991ad387e..832dee0e62 100644 --- a/Gems/TextureAtlas/gem.json +++ b/Gems/TextureAtlas/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Assets", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/utility/texture-atlas/" } diff --git a/Gems/TickBusOrderViewer/gem.json b/Gems/TickBusOrderViewer/gem.json index 787fd24abb..5ea936960a 100644 --- a/Gems/TickBusOrderViewer/gem.json +++ b/Gems/TickBusOrderViewer/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Gameplay", "Simulation", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/gameplay/tick-bus-order-viewer/" } diff --git a/Gems/Twitch/gem.json b/Gems/Twitch/gem.json index b5e2f3a3b2..6f875e9171 100644 --- a/Gems/Twitch/gem.json +++ b/Gems/Twitch/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Network", "SDK", "Multiplayer"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/network/twitch/twitch/" } diff --git a/Gems/UiBasics/gem.json b/Gems/UiBasics/gem.json index 9cd1548f57..d1e06eb15a 100644 --- a/Gems/UiBasics/gem.json +++ b/Gems/UiBasics/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["UI", "Assets", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/ui/ui-basics/" } diff --git a/Gems/Vegetation/gem.json b/Gems/Vegetation/gem.json index 1796123014..3119d67560 100644 --- a/Gems/Vegetation/gem.json +++ b/Gems/Vegetation/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Environment", "Tools", "Design"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/environment/vegetation/" } diff --git a/Gems/VideoPlaybackFramework/gem.json b/Gems/VideoPlaybackFramework/gem.json index 05598a8e5e..15b200c8db 100644 --- a/Gems/VideoPlaybackFramework/gem.json +++ b/Gems/VideoPlaybackFramework/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Rendering", "Framework"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/video-playback-framework/" } diff --git a/Gems/VirtualGamepad/gem.json b/Gems/VirtualGamepad/gem.json index 610f203f7c..472e8b93fe 100644 --- a/Gems/VirtualGamepad/gem.json +++ b/Gems/VirtualGamepad/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Input", "Gameplay"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/input/virtual-gamepad/" } diff --git a/Gems/WhiteBox/gem.json b/Gems/WhiteBox/gem.json index a46434dd65..0e44e2fe5e 100644 --- a/Gems/WhiteBox/gem.json +++ b/Gems/WhiteBox/gem.json @@ -8,5 +8,6 @@ "canonical_tags": ["Gem"], "user_tags": ["Design", "Tools", "Utility"], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/design/white-box/" } diff --git a/scripts/o3de/o3de/gem_properties.py b/scripts/o3de/o3de/gem_properties.py index c97e5db89d..39011a213a 100644 --- a/scripts/o3de/o3de/gem_properties.py +++ b/scripts/o3de/o3de/gem_properties.py @@ -53,6 +53,7 @@ def edit_gem_props(gem_path: pathlib.Path = None, new_summary: str = None, new_icon: str = None, new_requirements: str = None, + new_documentation_url: str = None, new_tags: list or str = None, remove_tags: list or str = None, replace_tags: list or str = None, @@ -90,7 +91,9 @@ def edit_gem_props(gem_path: pathlib.Path = None, if new_icon: update_key_dict['icon_path'] = new_icon if new_requirements: - update_key_dict['icon_requirements'] = new_requirements + update_key_dict['requirements'] = new_requirements + if new_documentation_url: + update_key_dict['documentation_url'] = new_documentation_url update_key_dict['user_tags'] = update_values_in_key_list(gem_json_data.get('user_tags', []), new_tags, remove_tags, replace_tags) @@ -110,6 +113,7 @@ def _edit_gem_props(args: argparse) -> int: args.gem_summary, args.gem_icon, args.gem_requirements, + args.gem_documentation_url, args.add_tags, args.remove_tags, args.replace_tags) @@ -129,20 +133,22 @@ def add_parser_args(parser): group.add_argument('-go', '--gem-origin', type=str, required=False, help='Sets description for gem origin.') group.add_argument('-gt', '--gem-type', type=str, required=False, choices=['Code', 'Tool', 'Asset'], - help='Sets the gem type. Can only be one of the selected choices') + help='Sets the gem type. Can only be one of the selected choices.') group.add_argument('-gs', '--gem-summary', type=str, required=False, help='Sets the summary description of the gem.') group.add_argument('-gi', '--gem-icon', type=str, required=False, help='Sets the path to the projects icon resource.') group.add_argument('-gr', '--gem-requirements', type=str, required=False, - help='Sets the description of the requirements needed to use the gem') + help='Sets the description of the requirements needed to use the gem.') + group.add_argument('-gdu', '--gem-documentation-url', type=str, required=False, + help='Sets the url for documentation of the gem.') group = parser.add_mutually_exclusive_group(required=False) group.add_argument('-at', '--add-tags', type=str, nargs='*', required=False, - help='Adds tag(s) to user_tags property. Can be specified multiple times') + help='Adds tag(s) to user_tags property. Can be specified multiple times.') group.add_argument('-dt', '--remove-tags', type=str, nargs='*', required=False, - help='Removes tag(s) from the user_tags property. Can be specified multiple times') + help='Removes tag(s) from the user_tags property. Can be specified multiple times.') group.add_argument('-rt', '--replace-tags', type=str, nargs='*', required=False, - help='Replace tag(s) in user_tags property. Can be specified multiple times') + help='Replace tag(s) in user_tags property. Can be specified multiple times.') parser.set_defaults(func=_edit_gem_props) diff --git a/scripts/o3de/tests/unit_test_gem_properties.py b/scripts/o3de/tests/unit_test_gem_properties.py index 29d53fbee6..5bfbe5573a 100644 --- a/scripts/o3de/tests/unit_test_gem_properties.py +++ b/scripts/o3de/tests/unit_test_gem_properties.py @@ -29,7 +29,8 @@ TEST_GEM_JSON_PAYLOAD = ''' "TestGem" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "documentation_url": "https://o3de.org/docs/" } ''' @@ -44,24 +45,26 @@ def init_gem_json_data(request): @pytest.mark.usefixtures('init_gem_json_data') class TestEditGemProperties: @pytest.mark.parametrize("gem_path, gem_name, gem_new_name, gem_display, gem_origin,\ - gem_type, gem_summary, gem_icon, gem_requirements,\ + gem_type, gem_summary, gem_icon, gem_requirements, gem_documentation_url,\ add_tags, remove_tags, replace_tags, expected_tags, expected_result", [ pytest.param(pathlib.PurePath('D:/TestProject'), None, 'TestGem2', 'New Gem Name', 'O3DE', 'Code', 'Gem that exercises Default Gem Template', - 'preview.png', '', + 'new_preview.png', 'Do this extra thing', 'https://o3de.org/docs/user-guide/gems/', ['Physics', 'Rendering', 'Scripting'], None, None, ['TestGem', 'Physics', 'Rendering', 'Scripting'], 0), pytest.param(None, 'TestGem2', None, 'New Gem Name', 'O3DE', 'Asset', 'Gem that exercises Default Gem Template', - 'preview.png', '', None, ['Physics'], None, ['TestGem', 'Rendering', 'Scripting'], 0), + 'new_preview.png', 'Do this extra thing', 'https://o3de.org/docs/user-guide/gems/', None, + ['Physics'], None, ['TestGem', 'Rendering', 'Scripting'], 0), pytest.param(None, 'TestGem2', None, 'New Gem Name', 'O3DE', 'Tool', 'Gem that exercises Default Gem Template', - 'preview.png', '', None, None, ['Animation', 'TestGem'], ['Animation', 'TestGem'], 0) + 'new_preview.png', 'Do this extra thing', 'https://o3de.org/docs/user-guide/gems/', None, + None, ['Animation', 'TestGem'], ['Animation', 'TestGem'], 0) ] ) def test_edit_gem_properties(self, gem_path, gem_name, gem_new_name, gem_display, gem_origin, - gem_type, gem_summary, gem_icon, gem_requirements, - add_tags, remove_tags, replace_tags, + gem_type, gem_summary, gem_icon, gem_requirements, + gem_documentation_url, add_tags, remove_tags, replace_tags, expected_tags, expected_result): def get_gem_json_data(gem_path: pathlib.Path) -> dict: @@ -79,7 +82,7 @@ class TestEditGemProperties: patch('o3de.manifest.get_registered', side_effect=get_gem_path) as get_registered_patch: result = gem_properties.edit_gem_props(gem_path, gem_name, gem_new_name, gem_display, gem_origin, gem_type, gem_summary, gem_icon, gem_requirements, - add_tags, remove_tags, replace_tags) + gem_documentation_url, add_tags, remove_tags, replace_tags) assert result == expected_result if gem_new_name: assert self.gem_json.data.get('gem_name', '') == gem_new_name @@ -94,6 +97,8 @@ class TestEditGemProperties: if gem_icon: assert self.gem_json.data.get('icon_path', '') == gem_icon if gem_requirements: - assert self.gem_json.data.get('requirments', '') == gem_requirements + assert self.gem_json.data.get('requirements', '') == gem_requirements + if gem_documentation_url: + assert self.gem_json.data.get('documentation_url', '') == gem_documentation_url assert set(self.gem_json.data.get('user_tags', [])) == set(expected_tags) From 9e0b8c564d4bc07d9479691bca0251a9ac194c01 Mon Sep 17 00:00:00 2001 From: moraaar Date: Fri, 6 Aug 2021 17:07:15 +0100 Subject: [PATCH 18/18] Fixed AzToolsFramework tests (#2887) * Fixed AzToolsFramework unit tests. Signed-off-by: moraaar * Include missing header. Signed-off-by: moraaar * Using util's class to generate temp directory, instead of qt. Signed-off-by: moraaar * Added empty line Signed-off-by: moraaar * Fixed warning in MessageTest fixture that CacheProjectRootFolder was not set Signed-off-by: moraaar * Additional checks in CreateDefaultEditorEntity helper function. Signed-off-by: moraaar * Updated the AzToolsFrameworkTest logic to set the project cache path The Project Cache Path and Project Path is set through the CommandLine functionality of the ComponentApplication. This allows those Project Cache Path and Project Path to be set within the Settings Registry during the ComponentApplication constructor Removed the explicitly calls to delete the temporary directory and fixed the ScopedTemporaryDirectory class to recursively delete the temporary directory Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Setup correctly @assets@ alias for PlatformAddressedAssetCatalogManagerTest and AssetSeedManagerTest fixtures. - These 2 test fixtures need to manually set the @asset@ alias to not include the platform at the end (which it does by default), because they are looping over platforms in their setup. - Also initializing pointers to nullptr, so if setup fail in the future the teardown doesn't crash trying to delete garbage. Signed-off-by: moraaar Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzFramework/Tests/Utils/Utils.cpp | 124 ++++++++++------- .../Framework/AzFramework/Tests/Utils/Utils.h | 3 + .../UnitTest/AzToolsFrameworkTestHelpers.cpp | 12 ++ .../UnitTest/ToolsTestApplication.cpp | 7 +- .../UnitTest/ToolsTestApplication.h | 1 + .../Tests/AssetFileInfoListComparison.cpp | 62 +++++---- .../Tests/AssetSeedManager.cpp | 121 ++++++----------- .../Tests/InstanceDataHierarchy.cpp | 24 ++-- .../PlatformAddressedAssetCatalogTests.cpp | 127 +++++++----------- 9 files changed, 236 insertions(+), 245 deletions(-) diff --git a/Code/Framework/AzFramework/Tests/Utils/Utils.cpp b/Code/Framework/AzFramework/Tests/Utils/Utils.cpp index cdc53a7e17..4f811a98ed 100644 --- a/Code/Framework/AzFramework/Tests/Utils/Utils.cpp +++ b/Code/Framework/AzFramework/Tests/Utils/Utils.cpp @@ -8,72 +8,100 @@ #include "Utils.h" #include +#include #include -UnitTest::ScopedTemporaryDirectory::ScopedTemporaryDirectory() +namespace UnitTest { - constexpr int MaxAttempts = 255; + void DeleteFolderRecursive(const AZ::IO::PathView& path) + { + auto callback = [&path](AZStd::string_view filename, bool isFile) -> bool + { + if (isFile) + { + auto filePath = AZ::IO::FixedMaxPath(path) / filename; + AZ::IO::SystemFile::Delete(filePath.c_str()); + } + else + { + if (filename != "." && filename != "..") + { + auto folderPath = AZ::IO::FixedMaxPath(path) / filename; + DeleteFolderRecursive(folderPath); + } + } + return true; + }; + auto searchPath = AZ::IO::FixedMaxPath(path) / "*"; + AZ::IO::SystemFile::FindFiles(searchPath.c_str(), callback); + AZ::IO::SystemFile::DeleteDir(AZ::IO::FixedMaxPathString(path.Native()).c_str()); + } + + + ScopedTemporaryDirectory::ScopedTemporaryDirectory() + { + constexpr int MaxAttempts = 255; #if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER - const auto userTempFolder = std::filesystem::temp_directory_path(); + const auto userTempFolder = std::filesystem::temp_directory_path(); #else - AZ::IO::Path userTempFolder("/tmp"); + AZ::IO::Path userTempFolder("/tmp"); #endif - for (int i = 0; i < MaxAttempts; ++i) - { - auto randomFolder = AZ::Uuid::CreateRandom().ToString>(false, false); - AZ::IO::FixedMaxPath testPath; -#if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER - auto path = userTempFolder / ("UnitTest-" + randomFolder).c_str(); - testPath = path.string().c_str(); -#else - userTempFolder /= ("UnitTest-" + randomFolder).c_str(); - testPath = userTempFolder.c_str(); -#endif - if (!AZ::IO::SystemFile::Exists(testPath.c_str())) + for (int i = 0; i < MaxAttempts; ++i) { -#if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER - m_path = path; - m_tempDirectory = m_path.string().c_str(); + auto randomFolder = AZ::Uuid::CreateRandom().ToString>(false, false); + AZ::IO::FixedMaxPath testPath; +#if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER + auto path = userTempFolder / ("UnitTest-" + randomFolder).c_str(); + testPath = path.string().c_str(); #else - m_tempDirectory = testPath; + userTempFolder /= ("UnitTest-" + randomFolder).c_str(); + testPath = userTempFolder.c_str(); #endif - m_directoryExists = AZ::IO::SystemFile::CreateDir(m_tempDirectory.c_str()); - break; + if (!AZ::IO::SystemFile::Exists(testPath.c_str())) + { +#if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER + m_path = path; + m_tempDirectory = m_path.string().c_str(); +#else + m_tempDirectory = testPath; +#endif + m_directoryExists = AZ::IO::SystemFile::CreateDir(m_tempDirectory.c_str()); + break; + } + } + + AZ_Error("ScopedTemporaryDirectory", !m_tempDirectory.empty(), "Failed to create unique temporary directory after attempting %d random folder names", MaxAttempts); + } + + ScopedTemporaryDirectory::~ScopedTemporaryDirectory() + { + if (m_directoryExists) + { + DeleteFolderRecursive(m_tempDirectory); } } - AZ_Error("ScopedTemporaryDirectory", !m_tempDirectory.empty(), "Failed to create unique temporary directory after attempting %d random folder names", MaxAttempts); -} - -UnitTest::ScopedTemporaryDirectory::~ScopedTemporaryDirectory() -{ - if (m_directoryExists) + bool ScopedTemporaryDirectory::IsValid() const { - AZ::IO::SystemFile::DeleteDir(m_tempDirectory.c_str()); + return m_directoryExists; } -} -bool UnitTest::ScopedTemporaryDirectory::IsValid() const -{ - return m_directoryExists; -} - -const char* UnitTest::ScopedTemporaryDirectory::GetDirectory() const -{ - return m_tempDirectory.c_str(); -} + const char* ScopedTemporaryDirectory::GetDirectory() const + { + return m_tempDirectory.c_str(); + } #if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER -const std::filesystem::path& UnitTest::ScopedTemporaryDirectory::GetPath() const -{ - return m_path; -} - -std::filesystem::path UnitTest::ScopedTemporaryDirectory::operator/(const std::filesystem::path& rhs) const -{ - return m_path / rhs; -} + const std::filesystem::path& ScopedTemporaryDirectory::GetPath() const + { + return m_path; + } + std::filesystem::path ScopedTemporaryDirectory::operator/(const std::filesystem::path& rhs) const + { + return m_path / rhs; + } #endif // !AZ_TRAIT_USE_POSIX_TEMP_FOLDER +} diff --git a/Code/Framework/AzFramework/Tests/Utils/Utils.h b/Code/Framework/AzFramework/Tests/Utils/Utils.h index 83a3a9dd42..b5fb5e8387 100644 --- a/Code/Framework/AzFramework/Tests/Utils/Utils.h +++ b/Code/Framework/AzFramework/Tests/Utils/Utils.h @@ -18,6 +18,9 @@ namespace UnitTest { + //! Deletes a folder hierarchy from the supplied path + void DeleteFolderRecursive(const AZ::IO::PathView& path); + // Creates a randomly named folder inside the user's temporary directory. // The folder and all contents will be destroyed when the object goes out of scope struct ScopedTemporaryDirectory diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp index 3f2cb24d69..5ffbe1b4f3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp @@ -352,8 +352,20 @@ namespace UnitTest AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( entityId, &AzToolsFramework::EditorEntityContextRequestBus::Events::CreateNewEditorEntity, name); + if (!entityId.IsValid()) + { + AZ_Error("CreateDefaultEditorEntity", false, "Failed to create editor entity '%s'", name); + return AZ::EntityId(); + } + AZ::Entity* entity = GetEntityById(entityId); + if (!entity) + { + AZ_Error("CreateDefaultEditorEntity", false, "Invalid entity obtained from Id %s", entityId.ToString().c_str()); + return AZ::EntityId(); + } + entity->Deactivate(); // add required components for the Editor entity diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.cpp index be9b332982..3ef1210233 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.cpp @@ -11,7 +11,12 @@ namespace UnitTest { ToolsTestApplication::ToolsTestApplication(AZStd::string applicationName) - : ToolsApplication() + :ToolsTestApplication(AZStd::move(applicationName), 0, nullptr) + { + } + + ToolsTestApplication::ToolsTestApplication(AZStd::string applicationName, int argc, char** argv) + : AzToolsFramework::ToolsApplication(&argc, &argv) , m_applicationName(AZStd::move(applicationName)) { } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.h index 22de71b2d8..2bf920cc4a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/ToolsTestApplication.h @@ -18,6 +18,7 @@ namespace UnitTest { public: explicit ToolsTestApplication(AZStd::string applicationName); + ToolsTestApplication(AZStd::string applicationName, int argc, char** argv); void SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) override; protected: diff --git a/Code/Framework/AzToolsFramework/Tests/AssetFileInfoListComparison.cpp b/Code/Framework/AzToolsFramework/Tests/AssetFileInfoListComparison.cpp index 4aa9dbe2bb..5ad68a2c1c 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetFileInfoListComparison.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetFileInfoListComparison.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -49,19 +50,22 @@ namespace UnitTest void SetUp() override { using namespace AZ::Data; - m_application = new ToolsTestApplication("AssetFileInfoListComparisonTest"); + constexpr size_t MaxCommandArgsCount = 128; + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using ArgumentContainer = AZStd::fixed_vector; + // The first command line argument is assumed to be the executable name so add a blank entry for it + ArgumentContainer argContainer{ {} }; + + // Append Command Line override for the Project Cache Path + auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", m_tempDir.GetDirectory()); + auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" }; + argContainer.push_back(projectCachePathOverride.data()); + argContainer.push_back(projectPathOverride.data()); + m_application = new ToolsTestApplication("AssetFileInfoListComparisonTest", aznumeric_caster(argContainer.size()), argContainer.data()); AzToolsFramework::AssetSeedManager assetSeedManager; AzFramework::AssetRegistry assetRegistry; - m_localFileIO = aznew AZ::IO::LocalFileIO(); - - m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); - AZ::IO::FileIOBase::SetInstance(nullptr); - AZ::IO::FileIOBase::SetInstance(m_localFileIO); - - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", m_tempDir.GetDirectory()); - - AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(AzFramework::PlatformId::PC); + const AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(AzFramework::PlatformId::PC); for (int idx = 0; idx < TotalAssets; idx++) { @@ -75,7 +79,8 @@ namespace UnitTest AZ_TEST_START_TRACE_SUPPRESSION; if (m_fileStreams[idx].Open(m_assetsPath[idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - m_fileStreams[idx].Write(info.m_relativePath.size(), info.m_relativePath.data()); + AZ::IO::SizeType bytesWritten = m_fileStreams[idx].Write(info.m_relativePath.size(), info.m_relativePath.data()); + EXPECT_EQ(bytesWritten, info.m_relativePath.size()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } else @@ -92,6 +97,7 @@ namespace UnitTest assetRegistry.RegisterAssetDependency(m_assets[3], AZ::Data::ProductDependency(m_assets[4], 0)); m_application->Start(AzFramework::Application::Descriptor()); + // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. @@ -109,14 +115,16 @@ namespace UnitTest AZStd::string pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC); - ASSERT_TRUE(AzFramework::AssetCatalog::SaveCatalog(pcCatalogFile.c_str(), &assetRegistry)) << "Unable to save the asset catalog file.\n"; + bool catalogSaved = AzFramework::AssetCatalog::SaveCatalog(pcCatalogFile.c_str(), &assetRegistry); + EXPECT_TRUE(catalogSaved) << "Unable to save the asset catalog file.\n"; m_pcCatalog = new AzToolsFramework::PlatformAddressedAssetCatalog(AzFramework::PlatformId::PC); assetSeedManager.AddSeedAsset(m_assets[0], AzFramework::PlatformFlags::Platform_PC); assetSeedManager.AddSeedAsset(m_assets[1], AzFramework::PlatformFlags::Platform_PC); - assetSeedManager.SaveAssetFileInfo(TempFiles[FileIndex::FirstAssetFileInfoList], AzFramework::PlatformFlags::Platform_PC, {}); + bool firstAssetFileInfoListSaved = assetSeedManager.SaveAssetFileInfo(TempFiles[FileIndex::FirstAssetFileInfoList], AzFramework::PlatformFlags::Platform_PC, {}); + EXPECT_TRUE(firstAssetFileInfoListSaved); // Modify contents of asset2 int fileIndex = 2; @@ -124,7 +132,8 @@ namespace UnitTest if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content - m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); + AZ::IO::SizeType bytesWritten = m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); + EXPECT_EQ(bytesWritten, fileContent.size()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } else @@ -138,7 +147,8 @@ namespace UnitTest if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content - m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); + AZ::IO::SizeType bytesWritten = m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); + EXPECT_EQ(bytesWritten, fileContent.size()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } else @@ -149,7 +159,8 @@ namespace UnitTest assetSeedManager.RemoveSeedAsset(m_assets[0], AzFramework::PlatformFlags::Platform_PC); assetSeedManager.AddSeedAsset(m_assets[5], AzFramework::PlatformFlags::Platform_PC); - assetSeedManager.SaveAssetFileInfo(TempFiles[FileIndex::SecondAssetFileInfoList], AzFramework::PlatformFlags::Platform_PC, {}); + bool secondAssetFileInfoListSaved = assetSeedManager.SaveAssetFileInfo(TempFiles[FileIndex::SecondAssetFileInfoList], AzFramework::PlatformFlags::Platform_PC, {}); + EXPECT_TRUE(secondAssetFileInfoListSaved); } void TearDown() override @@ -162,7 +173,8 @@ namespace UnitTest if (fileIO->Exists(TempFiles[idx])) { AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(TempFiles[idx]); + AZ::IO::Result result = fileIO->Remove(TempFiles[idx]); + EXPECT_EQ(result.GetResultCode(), AZ::IO::ResultCode::Success); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder } } @@ -175,7 +187,8 @@ namespace UnitTest if (fileIO->Exists(m_assetsPath[idx].c_str())) { AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(m_assetsPath[idx].c_str()); + AZ::IO::Result result = fileIO->Remove(m_assetsPath[idx].c_str()); + EXPECT_EQ(result.GetResultCode(), AZ::IO::ResultCode::Success); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder } } @@ -184,15 +197,12 @@ namespace UnitTest if (fileIO->Exists(pcCatalogFile.c_str())) { AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(pcCatalogFile.c_str()); + AZ::IO::Result result = fileIO->Remove(pcCatalogFile.c_str()); + EXPECT_EQ(result.GetResultCode(), AZ::IO::ResultCode::Success); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder } delete m_pcCatalog; - delete m_localFileIO; - m_localFileIO = nullptr; - AZ::IO::FileIOBase::SetInstance(nullptr); - AZ::IO::FileIOBase::SetInstance(m_priorFileIO); m_application->Stop(); delete m_application; @@ -742,11 +752,9 @@ namespace UnitTest } - ToolsTestApplication* m_application; + ToolsTestApplication* m_application = nullptr; UnitTest::ScopedTemporaryDirectory m_tempDir; - AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog; - AZ::IO::FileIOBase* m_priorFileIO = nullptr; - AZ::IO::FileIOBase* m_localFileIO = nullptr; + AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog = nullptr; AZ::IO::FileIOStream m_fileStreams[TotalAssets]; AZ::Data::AssetId m_assets[TotalAssets]; AZStd::string m_assetsPath[TotalAssets]; diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index 0b5c37ccc2..4083608370 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -23,11 +23,12 @@ #include #include #include +#include + namespace // anonymous { static const int s_totalAssets = 12; static const int s_totalTestPlatforms = 2; - const char* s_catalogFile = "AssetCatalog.xml"; AZ::Data::AssetId assets[s_totalAssets]; const char TestSliceAssetPath[] = "test.slice"; @@ -55,18 +56,30 @@ namespace UnitTest void SetUp() override { using namespace AZ::Data; - m_application = new ToolsTestApplication("AssetSeedManagerTest"); + constexpr size_t MaxCommandArgsCount = 128; + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using ArgumentContainer = AZStd::fixed_vector; + // The first command line argument is assumed to be the executable name so add a blank entry for it + ArgumentContainer argContainer{ {} }; + + // Append Command Line override for the Project Cache Path + AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() }; + auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str()); + auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" }; + argContainer.push_back(projectCachePathOverride.data()); + argContainer.push_back(projectPathOverride.data()); + m_application = new ToolsTestApplication("AssetSeedManagerTest", aznumeric_caster(argContainer.size()), argContainer.data()); m_assetSeedManager = new AzToolsFramework::AssetSeedManager(); m_assetRegistry = new AzFramework::AssetRegistry(); - AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get(); - auto projectPathKey = - AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; - registry->Set(projectPathKey, "AutomatedTesting"); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); - m_application->Start(AzFramework::Application::Descriptor()); + // By default @assets@ is setup to include the platform at the end. But this test is going to + // loop over platforms and it will be included as part of the relative path of the file. + // So the asset folder for these tests have to point to the cache project root folder, which + // doesn't include the platform. + AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); + for (int idx = 0; idx < s_totalAssets; idx++) { assets[idx] = AssetId(AZ::Uuid::CreateRandom(), 0); @@ -83,17 +96,18 @@ namespace UnitTest int platformCount = 0; for(auto thisPlatform : m_testPlatforms) { - AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(thisPlatform); + AZ::IO::Path assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(thisPlatform); for (int idx = 0; idx < s_totalAssets; idx++) { - AzFramework::StringFunc::Path::Join(assetRoot.c_str(), m_assetsPath[idx].c_str(), m_assetsPathFull[platformCount][idx]); + m_assetsPathFull[platformCount][idx] = (assetRoot / m_assetsPath[idx]).Native(); AZ_TEST_START_TRACE_SUPPRESSION; if (m_fileStreams[platformCount][idx].Open(m_assetsPathFull[platformCount][idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - m_fileStreams[platformCount][idx].Write(m_assetsPath[idx].size(), m_assetsPath[idx].data()); + AZ::IO::SizeType bytesWritten = m_fileStreams[platformCount][idx].Write(m_assetsPath[idx].size(), m_assetsPath[idx].data()); + EXPECT_EQ(bytesWritten, m_assetsPath[idx].size()); m_fileStreams[platformCount][idx].Close(); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, only invalid for PC, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } else { @@ -117,7 +131,7 @@ namespace UnitTest AZ_TEST_START_TRACE_SUPPRESSION; AZ::IO::FileIOStream dynamicSliceFileIOStream(TestDynamicSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder AZ::Data::AssetInfo sliceAssetInfo; sliceAssetInfo.m_relativePath = TestSliceAssetPath; @@ -131,7 +145,7 @@ namespace UnitTest AZ_TEST_START_TRACE_SUPPRESSION; AZ::IO::FileIOStream sliceFileIOStream(TestSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder // asset0 -> asset1 -> asset2 -> asset4 // --> asset3 @@ -197,58 +211,6 @@ namespace UnitTest void TearDown() override { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - - if (fileIO->Exists(s_catalogFile)) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(s_catalogFile); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins - } - - for (size_t platformCount = 0; platformCount < s_totalTestPlatforms; ++platformCount) - { - // Deleting all the temporary files - for (int idx = 0; idx < s_totalAssets; idx++) - { - // we need to close the handle before we try to remove the file - if (fileIO->Exists(m_assetsPathFull[platformCount][idx].c_str())) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(m_assetsPathFull[platformCount][idx].c_str()); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins - } - } - } - - if (fileIO->Exists(TestSliceAssetPath)) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(TestSliceAssetPath); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins - } - - if (fileIO->Exists(TestDynamicSliceAssetPath)) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(TestDynamicSliceAssetPath); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins - } - - auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC); - auto androidCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID); - if (fileIO->Exists(pcCatalogFile.c_str())) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(pcCatalogFile.c_str()); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins - } - - if (fileIO->Exists(androidCatalogFile.c_str())) - { - fileIO->Remove(androidCatalogFile.c_str()); - } - delete m_assetSeedManager; delete m_assetRegistry; delete m_pcCatalog; @@ -284,7 +246,7 @@ namespace UnitTest // Attempt to save to the same file. Should not be allowed. AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_FALSE(m_assetSeedManager->Save(filePath)); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // One error expected // Clean up the test environment AZ::IO::SystemFile::SetWritable(filePath.c_str(), true); @@ -310,7 +272,7 @@ namespace UnitTest // Attempt to save to the same file. Should not be allowed. AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_FALSE(m_assetSeedManager->SaveAssetFileInfo(filePath, AzFramework::PlatformFlags::Platform_PC, {})); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // One error expected // Clean up the test environment AZ::IO::SystemFile::SetWritable(filePath.c_str(), true); @@ -379,7 +341,7 @@ namespace UnitTest // Step we are testing AZ_TEST_START_TRACE_SUPPRESSION; m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ANDROID_ID); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // One error expected // Verification AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID; @@ -649,9 +611,10 @@ namespace UnitTest if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex); - m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); + AZ::IO::SizeType bytesWritten = m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); + EXPECT_EQ(bytesWritten, fileContent.size()); m_fileStreams[0][fileIndex].Close(); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); @@ -682,9 +645,10 @@ namespace UnitTest if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content - m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); + AZ::IO::SizeType bytesWritten = m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); + EXPECT_EQ(bytesWritten, fileContent.size()); m_fileStreams[0][fileIndex].Close(); - AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); @@ -790,16 +754,17 @@ namespace UnitTest } - AzToolsFramework::AssetSeedManager* m_assetSeedManager; - AzFramework::AssetRegistry* m_assetRegistry; - ToolsTestApplication* m_application; - AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog; - AzToolsFramework::PlatformAddressedAssetCatalog* m_androidCatalog; + AzToolsFramework::AssetSeedManager* m_assetSeedManager = nullptr; + AzFramework::AssetRegistry* m_assetRegistry = nullptr; + ToolsTestApplication* m_application = nullptr; + AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog = nullptr; + AzToolsFramework::PlatformAddressedAssetCatalog* m_androidCatalog = nullptr; AZ::IO::FileIOStream m_fileStreams[s_totalTestPlatforms][s_totalAssets]; AzFramework::PlatformId m_testPlatforms[s_totalTestPlatforms]; AZStd::string m_assetsPath[s_totalAssets]; AZStd::string m_assetsPathFull[s_totalTestPlatforms][s_totalAssets]; AZ::Data::AssetId m_testDynamicSliceAssetId; + UnitTest::ScopedTemporaryDirectory m_tempDir; }; TEST_F(AssetSeedManagerTest, AssetSeedManager_SaveSeedListFile_FileIsReadOnly) diff --git a/Code/Framework/AzToolsFramework/Tests/InstanceDataHierarchy.cpp b/Code/Framework/AzToolsFramework/Tests/InstanceDataHierarchy.cpp index 1b11479bff..806a3bbab2 100644 --- a/Code/Framework/AzToolsFramework/Tests/InstanceDataHierarchy.cpp +++ b/Code/Framework/AzToolsFramework/Tests/InstanceDataHierarchy.cpp @@ -1285,7 +1285,7 @@ namespace UnitTest Crc32 uiHandler = 0; EXPECT_EQ(it->ReadAttribute(AZ::Edit::UIHandlers::Handler, uiHandler), true); EXPECT_EQ(uiHandler, AZ_CRC("TestHandler")); - EXPECT_EQ(it->GetElementMetadata()->m_name, "UIElement"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "UIElement"); EXPECT_EQ(it->GetElementMetadata()->m_nameCrc, AZ_CRC("UIElement")); uiHandler = 0; @@ -1293,7 +1293,7 @@ namespace UnitTest ++it; EXPECT_EQ(it->ReadAttribute(AZ::Edit::UIHandlers::Handler, uiHandler), true); EXPECT_EQ(uiHandler, AZ_CRC("TestHandler2")); - EXPECT_EQ(it->GetElementMetadata()->m_name, "UIElement2"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "UIElement2"); EXPECT_EQ(it->GetElementMetadata()->m_nameCrc, AZ_CRC("UIElement2")); } }; @@ -1356,21 +1356,21 @@ namespace UnitTest auto it = children.begin(); - EXPECT_EQ(it->GetElementMetadata()->m_name, "aggregatedDataElement"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "aggregatedDataElement"); ++it; if (i == 0) { - EXPECT_EQ(it->GetElementMetadata()->m_name, "notAggregatedDataElement"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "notAggregatedDataElement"); ++it; } - EXPECT_EQ(it->GetElementMetadata()->m_name, "aggregatedUIElement"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "aggregatedUIElement"); ++it; if (i == 0) { - EXPECT_EQ(it->GetElementMetadata()->m_name, "notAggregatedUIElement"); + EXPECT_STREQ(it->GetElementMetadata()->m_name, "notAggregatedUIElement"); ++it; } } @@ -1505,11 +1505,11 @@ namespace UnitTest AZStd::string childName(child.GetElementMetadata()->m_name); if (childName.compare("GroupFloat") == 0) { - EXPECT_EQ(child.GetGroupElementMetadata()->m_description, "Normal Group"); + EXPECT_STREQ(child.GetGroupElementMetadata()->m_description, "Normal Group"); } if (childName.compare("ToggleGroupInt") == 0) { - EXPECT_EQ(child.GetGroupElementMetadata()->m_description, "Group Toggle"); + EXPECT_STREQ(child.GetGroupElementMetadata()->m_description, "Group Toggle"); } if ((childName.compare("SubDataNormal") == 0) || (childName.compare("SubDataToggle") == 0)) { @@ -1518,11 +1518,11 @@ namespace UnitTest childName = subChild.GetElementMetadata()->m_name; if (childName.compare("SubInt") == 0) { - EXPECT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); + EXPECT_STREQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); } if (childName.compare("SubFloat") == 0) { - EXPECT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); + EXPECT_STREQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); } } } @@ -1552,7 +1552,7 @@ namespace UnitTest AZStd::string childName(child.GetElementMetadata()->m_name); if (childName.compare(paramName) == 0) { - EXPECT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + EXPECT_STREQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); } if ((childName.compare("SubDataNormal") == 0) || (childName.compare("SubDataToggle") == 0)) { @@ -1561,7 +1561,7 @@ namespace UnitTest childName = subChild.GetElementMetadata()->m_name; if (childName.compare(paramName) == 0) { - EXPECT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + EXPECT_STREQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); } } } diff --git a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp index 00a7b1973c..67d40be376 100644 --- a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp @@ -19,9 +19,8 @@ #include #include #include -#include -#include #include +#include namespace { @@ -35,25 +34,22 @@ namespace UnitTest { public: - AZStd::string GetTempFolder() - { - QTemporaryDir dir; - QDir tempPath(dir.path()); - return tempPath.absolutePath().toUtf8().data(); - } - void SetUp() override { using namespace AZ::Data; - m_application = new ToolsTestApplication("AddressedAssetCatalogManager"); // Shorter name because Setting Registry - // specialization are 32 characters max. + constexpr size_t MaxCommandArgsCount = 128; + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using ArgumentContainer = AZStd::fixed_vector; + // The first command line argument is assumed to be the executable name so add a blank entry for it + ArgumentContainer argContainer{ {} }; - AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get(); - - auto projectPathKey = - AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; - registry->Set(projectPathKey, "AutomatedTesting"); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); + // Append Command Line override for the Project Cache Path + AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() }; + auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str()); + auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" }; + argContainer.push_back(projectCachePathOverride.data()); + argContainer.push_back(projectPathOverride.data()); + m_application = new ToolsTestApplication("AddressedAssetCatalogManager", aznumeric_caster(argContainer.size()), argContainer.data()); m_application->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is @@ -61,33 +57,36 @@ namespace UnitTest // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - AZStd::string cacheFolder; - AzFramework::StringFunc::Path::Join(GetTempFolder().c_str(), "testplatform", cacheFolder); - AzFramework::StringFunc::Path::Join(cacheFolder.c_str(), "testproject", cacheFolder); - - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheFolder.c_str()); + // By default @assets@ is setup to include the platform at the end. But this test is going to + // loop over all platforms and it will be included as part of the relative path of the file. + // So the asset folder for these tests have to point to the cache project root folder, which + // doesn't include the platform. + AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum) { - AZStd::string platformName{ AzFramework::PlatformHelper::GetPlatformName(static_cast(platformNum)) }; + const AZStd::string platformName{ AzFramework::PlatformHelper::GetPlatformName(static_cast(platformNum)) }; if (!platformName.length()) { // Do not test disabled platforms continue; } + AZStd::unique_ptr assetRegistry = AZStd::make_unique(); for (int idx = 0; idx < s_totalAssets; idx++) { m_assets[platformNum][idx] = AssetId(AZ::Uuid::CreateRandom(), 0); AZ::Data::AssetInfo info; - info.m_relativePath = AZStd::string::format("%s%sAsset%d_%s.txt", cacheFolder.c_str(), AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING, idx, platformName.c_str()); + info.m_relativePath = AZStd::move((AZ::IO::Path(platformName) / AZStd::string::format("Asset%d.txt", idx)).Native()); info.m_assetId = m_assets[platformNum][idx]; assetRegistry->RegisterAsset(m_assets[platformNum][idx], info); - m_assetsPath[platformNum][idx] = info.m_relativePath; + m_assetsPath[platformNum][idx] = AZStd::move((cacheProjectRootFolder / info.m_relativePath).Native()); AZ_TEST_START_TRACE_SUPPRESSION; if (m_fileStreams[platformNum][idx].Open(m_assetsPath[platformNum][idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - m_fileStreams[platformNum][idx].Write(info.m_relativePath.size(), info.m_relativePath.data()); + AZ::IO::SizeType bytesWritten = m_fileStreams[platformNum][idx].Write(info.m_relativePath.size(), info.m_relativePath.data()); + EXPECT_EQ(bytesWritten, info.m_relativePath.size()); + m_fileStreams[platformNum][idx].Close(); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder } else @@ -112,48 +111,15 @@ namespace UnitTest void TearDown() override { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum) - { - AZStd::string platformName{ AzFramework::PlatformHelper::GetPlatformName(static_cast(platformNum)) }; - if (!platformName.length()) - { - // Do not test disabled platforms - continue; - } - AZStd::string catalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(static_cast(platformNum)); - - if (fileIO->Exists(catalogPath.c_str())) - { - fileIO->Remove(catalogPath.c_str()); - } - // Deleting all the temporary files - for (int idx = 0; idx < s_totalAssets; idx++) - { - // we need to close the handle before we try to remove the file - m_fileStreams[platformNum][idx].Close(); - if (fileIO->Exists(m_assetsPath[platformNum][idx].c_str())) - { - AZ_TEST_START_TRACE_SUPPRESSION; - fileIO->Remove(m_assetsPath[platformNum][idx].c_str()); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); // removing from asset cache folder - } - } - } - - delete m_localFileIO; - m_localFileIO = nullptr; - AZ::IO::FileIOBase::SetInstance(m_priorFileIO); delete m_PlatformAddressedAssetCatalogManager; m_application->Stop(); delete m_application; } - AzToolsFramework::PlatformAddressedAssetCatalogManager* m_PlatformAddressedAssetCatalogManager; - ToolsTestApplication* m_application; - AZ::IO::FileIOBase* m_priorFileIO = nullptr; - AZ::IO::FileIOBase* m_localFileIO = nullptr; + AzToolsFramework::PlatformAddressedAssetCatalogManager* m_PlatformAddressedAssetCatalogManager = nullptr; + ToolsTestApplication* m_application = nullptr; + UnitTest::ScopedTemporaryDirectory m_tempDir; AZ::IO::FileIOStream m_fileStreams[AzFramework::PlatformId::NumPlatformIds][s_totalAssets]; AZ::Data::AssetId m_assets[AzFramework::PlatformId::NumPlatformIds][s_totalAssets]; @@ -183,12 +149,14 @@ namespace UnitTest TEST_F(PlatformAddressedAssetCatalogManagerTest, PlatformAddressedAssetCatalogManager_CatalogExistsChecks_Success) { - EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), true); AZStd::string androidCatalogPath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID); if (AZ::IO::FileIOBase::GetInstance()->Exists(androidCatalogPath.c_str())) { - AZ::IO::FileIOBase::GetInstance()->Remove(androidCatalogPath.c_str()); + AZ_TEST_START_TRACE_SUPPRESSION; + AZ::IO::Result result = AZ::IO::FileIOBase::GetInstance()->Remove(androidCatalogPath.c_str()); + EXPECT_EQ(result.GetResultCode(), AZ::IO::ResultCode::Success); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // removing from asset cache folder } EXPECT_EQ(AzToolsFramework::PlatformAddressedAssetCatalog::CatalogExists(AzFramework::PlatformId::ANDROID_ID), false); } @@ -218,31 +186,32 @@ namespace UnitTest : public AllocatorsFixture { public: - AZStd::string GetTempFolder() - { - QTemporaryDir dir; - QDir tempPath(dir.path()); - return tempPath.absolutePath().toUtf8().data(); - } - void SetUp() override { - AZ::IO::FileIOBase::SetInstance(nullptr); // The API requires the old instance to be destroyed first - AZ::IO::FileIOBase::SetInstance(new AZ::IO::LocalFileIO()); + constexpr size_t MaxCommandArgsCount = 128; + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using ArgumentContainer = AZStd::fixed_vector; + // The first command line argument is assumed to be the executable name so add a blank entry for it + ArgumentContainer argContainer{ {} }; - AZStd::string cacheFolder; - AzFramework::StringFunc::Path::Join(GetTempFolder().c_str(), "testplatform", cacheFolder); - AzFramework::StringFunc::Path::Join(cacheFolder.c_str(), "testproject", cacheFolder); - - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheFolder.c_str()); + // Append Command Line override for the Project Cache Path + AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() }; + auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str()); + auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" }; + argContainer.push_back(projectCachePathOverride.data()); + argContainer.push_back(projectPathOverride.data()); + m_application = new ToolsTestApplication("MessageTest", aznumeric_caster(argContainer.size()), argContainer.data()); m_platformAddressedAssetCatalogManager = AZStd::make_unique(AzFramework::PlatformId::Invalid); } void TearDown() override { m_platformAddressedAssetCatalogManager.reset(); + delete m_application; } + ToolsTestApplication* m_application = nullptr; AZStd::unique_ptr m_platformAddressedAssetCatalogManager; + UnitTest::ScopedTemporaryDirectory m_tempDir; }; TEST_F(MessageTest, PlatformAddressedAssetCatalogManagerMessageTest_MessagesForwarded_CountsMatch) @@ -253,7 +222,7 @@ namespace UnitTest AZ_TEST_START_TRACE_SUPPRESSION; auto* mockCatalog = new ::testing::NiceMock(AzFramework::PlatformId::ANDROID_ID); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Expected error not finding catalog AZStd::unique_ptr< ::testing::NiceMock> catalogHolder; catalogHolder.reset(mockCatalog);