Merge pull request #3394 from aws-lumberyard-dev/Budgets
Add budget registration/tracking system and prepare driller redcode
This commit is contained in:
@@ -1047,7 +1047,7 @@ static bool TryRenameFile(const QString& oldPath, const QString& newPath, int re
|
||||
|
||||
bool CCryEditDoc::SaveLevel(const QString& filename)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
AZ_PROFILE_FUNCTION(Editor);
|
||||
QWaitCursor wait;
|
||||
|
||||
CAutoCheckOutDialogEnableForAll enableForAll;
|
||||
@@ -1067,7 +1067,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
|
||||
|
||||
{
|
||||
|
||||
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel BackupBeforeSave");
|
||||
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel BackupBeforeSave");
|
||||
BackupBeforeSave();
|
||||
}
|
||||
|
||||
@@ -1178,7 +1178,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
|
||||
CPakFile pakFile;
|
||||
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Open PakFile");
|
||||
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel Open PakFile");
|
||||
if (!pakFile.Open(tempSaveFile.toUtf8().data(), false))
|
||||
{
|
||||
gEnv->pLog->LogWarning("Unable to open pack file %s for writing", tempSaveFile.toUtf8().data());
|
||||
@@ -1209,7 +1209,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
|
||||
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> entitySaveStream(&entitySaveBuffer);
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Save Entities To Stream");
|
||||
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel Save Entities To Stream");
|
||||
EBUS_EVENT_RESULT(
|
||||
savedEntities, AzToolsFramework::EditorEntityContextRequestBus, SaveToStreamForEditor, entitySaveStream, layerEntities,
|
||||
instancesInLayers);
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_EDITOR_EDITORDEFS_H
|
||||
#define CRYINCLUDE_EDITOR_EDITORDEFS_H
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
|
||||
@@ -186,5 +184,3 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EDITORDEFS_H
|
||||
|
||||
@@ -393,8 +393,6 @@ void EditorViewportWidget::UpdateContent(int flags)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void EditorViewportWidget::Update()
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
if (Editor::EditorQtApplication::instance()->isMovingOrResizing())
|
||||
{
|
||||
return;
|
||||
@@ -956,15 +954,11 @@ AzFramework::CameraState EditorViewportWidget::GetCameraState()
|
||||
|
||||
AZ::Vector3 EditorViewportWidget::PickTerrain(const AzFramework::ScreenPoint& point)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
return LYVec3ToAZVec3(ViewToWorld(AzToolsFramework::ViewportInteraction::QPointFromScreenPoint(point), nullptr, true));
|
||||
}
|
||||
|
||||
AZ::EntityId EditorViewportWidget::PickEntity(const AzFramework::ScreenPoint& point)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
PreWidgetRendering();
|
||||
|
||||
AZ::EntityId entityId;
|
||||
@@ -991,8 +985,6 @@ float EditorViewportWidget::TerrainHeight(const AZ::Vector2& position)
|
||||
|
||||
void EditorViewportWidget::FindVisibleEntities(AZStd::vector<AZ::EntityId>& visibleEntitiesOut)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
visibleEntitiesOut.assign(m_entityVisibilityQuery.Begin(), m_entityVisibilityQuery.End());
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_IEDITOR_H
|
||||
#define CRYINCLUDE_EDITOR_IEDITOR_H
|
||||
#pragma once
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
@@ -25,6 +22,7 @@
|
||||
#include <WinWidgetId.h>
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
|
||||
class QMenu;
|
||||
|
||||
@@ -738,4 +736,5 @@ struct IInitializeUIInfo
|
||||
virtual void SetInfoText(const char* text) = 0;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_IEDITOR_H
|
||||
AZ_DECLARE_BUDGET(Editor);
|
||||
|
||||
|
||||
@@ -405,8 +405,6 @@ void CEditorImpl::Update()
|
||||
// Make sure this is not called recursively
|
||||
m_bUpdates = false;
|
||||
|
||||
FUNCTION_PROFILER(GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
//@FIXME: Restore this latter.
|
||||
//if (GetGameEngine() && GetGameEngine()->IsLevelLoaded())
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
// To use the Andrew's algorithm in order to make convex hull from the points, this header is needed.
|
||||
#include "Util/GeometryUtil.h"
|
||||
|
||||
|
||||
namespace {
|
||||
QColor kLinkColorParent = QColor(0, 255, 255);
|
||||
QColor kLinkColorChild = QColor(0, 0, 255);
|
||||
@@ -1928,7 +1927,7 @@ bool CBaseObject::HitTestRectBounds(HitContext& hc, const AABB& box)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CBaseObject::HitTestRect(HitContext& hc)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
AZ_PROFILE_FUNCTION(Editor);
|
||||
|
||||
AABB box;
|
||||
|
||||
@@ -1965,7 +1964,7 @@ bool CBaseObject::HitHelperTest(HitContext& hc)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CBaseObject::HitHelperAtTest(HitContext& hc, const Vec3& pos)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
AZ_PROFILE_FUNCTION(Editor);
|
||||
|
||||
bool bResult = false;
|
||||
|
||||
|
||||
@@ -1261,10 +1261,6 @@ void DisplayContext::DrawTextureLabel(const Vec3& pos, int nWidth, int nHeight,
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void DisplayContext::Flush2D()
|
||||
{
|
||||
#ifndef PHYSICS_EDITOR
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
#endif
|
||||
|
||||
if (m_textureLabels.empty())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -497,7 +497,7 @@ bool CEntityObject::HitTestRect(HitContext& hc)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int CEntityObject::MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Editor);
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
if (event == eMouseMove || event == eMouseLDown)
|
||||
{
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CGizmoManager::Display(DisplayContext& dc)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
AABB bbox;
|
||||
std::vector<CGizmo*> todelete;
|
||||
for (Gizmos::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
|
||||
@@ -37,7 +37,6 @@ AZ_CVAR(
|
||||
bool, ed_visibility_use, true, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"Enable/disable using the new IVisibilitySystem for Entity visibility determination");
|
||||
|
||||
|
||||
/*!
|
||||
* Class Description used for object templates.
|
||||
* This description filled from Xml template files.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "Objects/ObjectLoader.h"
|
||||
#include "Objects/SelectionGroup.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CUndoBaseObjectNew implementation.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneUI/CommonWidgets/OverlayWidget.h>
|
||||
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
ImporterRootDisplay::ImporterRootDisplay(AZ::SerializeContext* serializeContext, QWidget* parent)
|
||||
|
||||
@@ -148,8 +148,6 @@ void QTopRendererWnd::UpdateContent(int flags)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void QTopRendererWnd::Draw([[maybe_unused]] DisplayContext& dc)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Perform the rendering for this window
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -41,7 +41,6 @@ struct SPointSorter
|
||||
//===================================================================
|
||||
void ConvexHull2DGraham(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsIn)
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
|
||||
const unsigned nPtsIn = ptsIn.size();
|
||||
if (nPtsIn < 3)
|
||||
{
|
||||
@@ -66,7 +65,6 @@ void ConvexHull2DGraham(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsI
|
||||
|
||||
std::swap(ptsSorted[0], ptsSorted[iBotRight]);
|
||||
{
|
||||
FRAME_PROFILER("SORT Graham", gEnv->pSystem, PROFILE_AI)
|
||||
std::sort(ptsSorted.begin() + 1, ptsSorted.end(), SPointSorter(ptsSorted[0]));
|
||||
}
|
||||
ptsSorted.erase(std::unique(ptsSorted.begin(), ptsSorted.end(), ptEqual), ptsSorted.end());
|
||||
@@ -196,7 +194,6 @@ inline bool PointSorterAndrew(const Vec3& lhs, const Vec3& rhs)
|
||||
//===================================================================
|
||||
SANDBOX_API void ConvexHull2DAndrew(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsIn)
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
|
||||
const int n = (int)ptsIn.size();
|
||||
if (n < 3)
|
||||
{
|
||||
@@ -206,7 +203,6 @@ SANDBOX_API void ConvexHull2DAndrew(std::vector<Vec3>& ptsOut, const std::vector
|
||||
|
||||
std::vector<Vec3> P = ptsIn;
|
||||
{
|
||||
FRAME_PROFILER("SORT Andrew", gEnv->pSystem, PROFILE_AI)
|
||||
std::sort(P.begin(), P.end(), PointSorterAndrew);
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +400,6 @@ void QtViewport::UpdateContent(int flags)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void QtViewport::Update()
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
m_viewportUi.Update();
|
||||
|
||||
m_bAdvancedSelectMode = false;
|
||||
@@ -1436,9 +1435,6 @@ bool QtViewport::MouseCallback(EMouseEvent event, const QPoint& point, Qt::Keybo
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void QtViewport::ProcessRenderLisneters(DisplayContext& rstDisplayContext)
|
||||
{
|
||||
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
|
||||
|
||||
|
||||
size_t nCount(0);
|
||||
size_t nTotal(0);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
// Component includes
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/Jobs/JobManagerComponent.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
@@ -36,7 +35,6 @@ namespace AZ
|
||||
JsonSystemComponent::CreateDescriptor(),
|
||||
AssetManagerComponent::CreateDescriptor(),
|
||||
UserSettingsComponent::CreateDescriptor(),
|
||||
Debug::FrameProfilerComponent::CreateDescriptor(),
|
||||
SliceComponent::CreateDescriptor(),
|
||||
SliceSystemComponent::CreateDescriptor(),
|
||||
SliceMetadataInfoComponent::CreateDescriptor(),
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDriller.h>
|
||||
#include <AzCore/Debug/TraceMessagesDriller.h>
|
||||
#include <AzCore/Debug/ProfilerDriller.h>
|
||||
#include <AzCore/Debug/EventTraceDriller.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Script/ScriptSystemBus.h>
|
||||
@@ -546,6 +545,10 @@ namespace AZ
|
||||
m_entityActivatedEvent.DisconnectAllHandlers();
|
||||
m_entityDeactivatedEvent.DisconnectAllHandlers();
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
m_budgetTracker.Reset();
|
||||
#endif
|
||||
|
||||
DestroyAllocator();
|
||||
}
|
||||
|
||||
@@ -594,6 +597,10 @@ namespace AZ
|
||||
CreateOSAllocator();
|
||||
CreateSystemAllocator();
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
m_budgetTracker.Init();
|
||||
#endif
|
||||
|
||||
// This can be moved to the ComponentApplication constructor if need be
|
||||
// This is reading the *.setreg files using SystemFile and merging the settings
|
||||
// to the settings registry.
|
||||
@@ -625,8 +632,6 @@ namespace AZ
|
||||
m_eventLogger->Start(outputPath.Native(), baseFileName);
|
||||
}
|
||||
|
||||
CreateDrillers();
|
||||
|
||||
Sfmt::Create();
|
||||
|
||||
CreateReflectionManager();
|
||||
@@ -746,12 +751,6 @@ namespace AZ
|
||||
ComponentApplicationBus::Handler::BusDisconnect();
|
||||
TickRequestBus::Handler::BusDisconnect();
|
||||
|
||||
if (m_drillerManager)
|
||||
{
|
||||
Debug::DrillerManager::Destroy(m_drillerManager);
|
||||
m_drillerManager = nullptr;
|
||||
}
|
||||
|
||||
m_eventLogger->Stop();
|
||||
|
||||
// Clear the descriptor to deallocate all strings (owned by ModuleDescriptor)
|
||||
@@ -899,33 +898,6 @@ namespace AZ
|
||||
allocatorManager.FinalizeConfiguration();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CreateDrillers
|
||||
// [2/20/2013]
|
||||
//=========================================================================
|
||||
void ComponentApplication::CreateDrillers()
|
||||
{
|
||||
// Create driller manager and register drillers if requested
|
||||
if (m_descriptor.m_enableDrilling)
|
||||
{
|
||||
m_drillerManager = Debug::DrillerManager::Create();
|
||||
// Memory driller is responsible for tracking allocations.
|
||||
// Tracking type and overhead is determined by app configuration.
|
||||
|
||||
// Only one MemoryDriller is supported at a time
|
||||
// Only create the memory driller if there is no handlers connected to the MemoryDrillerBus
|
||||
if (!Debug::MemoryDrillerBus::HasHandlers())
|
||||
{
|
||||
m_drillerManager->Register(aznew Debug::MemoryDriller);
|
||||
}
|
||||
// Profiler driller will consume resources only when started.
|
||||
m_drillerManager->Register(aznew Debug::ProfilerDriller);
|
||||
// Trace messages driller will consume resources only when started.
|
||||
m_drillerManager->Register(aznew Debug::TraceMessagesDriller);
|
||||
m_drillerManager->Register(aznew Debug::EventTraceDriller);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry)
|
||||
{
|
||||
SettingsRegistryInterface::Specializations specializations;
|
||||
@@ -1416,10 +1388,6 @@ namespace AZ
|
||||
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
|
||||
}
|
||||
}
|
||||
if (m_drillerManager)
|
||||
{
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
#include <AzCore/Module/ModuleManager.h>
|
||||
@@ -225,11 +226,6 @@ namespace AZ
|
||||
/// Returns the path to the folder the executable is in.
|
||||
const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); }
|
||||
|
||||
|
||||
/// Returns pointer to the driller manager if it's enabled, otherwise NULL.
|
||||
Debug::DrillerManager* GetDrillerManager() override { return m_drillerManager; }
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// TickRequestBus
|
||||
float GetTickDeltaTime() override;
|
||||
@@ -324,9 +320,6 @@ namespace AZ
|
||||
/// Create the system allocator using the data in the m_descriptor
|
||||
void CreateSystemAllocator();
|
||||
|
||||
/// Create the drillers
|
||||
void CreateDrillers();
|
||||
|
||||
virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry);
|
||||
|
||||
//! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived
|
||||
@@ -402,6 +395,10 @@ namespace AZ
|
||||
// from the m_console member when it goes out of scope
|
||||
AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle m_settingsRegistryConsoleFunctors;
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
Debug::BudgetTracker m_budgetTracker;
|
||||
#endif
|
||||
|
||||
// this is used when no argV/ArgC is supplied.
|
||||
// in order to have the same memory semantics (writable, non-const)
|
||||
// we create a buffer that can be written to (up to AZ_MAX_PATH_LEN) and then
|
||||
@@ -409,8 +406,6 @@ namespace AZ
|
||||
char m_commandLineBuffer[AZ_MAX_PATH_LEN];
|
||||
char* m_commandLineBufferAddress{ m_commandLineBuffer };
|
||||
|
||||
Debug::DrillerManager* m_drillerManager{ nullptr };
|
||||
|
||||
StartupParameters m_startupParameters;
|
||||
|
||||
char** m_argV{ nullptr };
|
||||
|
||||
@@ -187,11 +187,6 @@ namespace AZ
|
||||
//! @return a pointer to the name of the path that contains the application's executable.
|
||||
virtual const char* GetExecutableFolder() const = 0;
|
||||
|
||||
//! Returns a pointer to the driller manager, if driller is enabled.
|
||||
//! The driller manager manages all active driller sessions and driller factories.
|
||||
//! @return A pointer to the driller manager. If driller is not enabled, this function returns null.
|
||||
virtual Debug::DrillerManager* GetDrillerManager() = 0;
|
||||
|
||||
//! ResolveModulePath is called whenever LoadDynamicModule wants to resolve a module in order to actually load it.
|
||||
//! You can override this if you need to load modules from a different path or hijack module loading in some other way.
|
||||
//! If you do, ensure that you use platform-specific conventions to do so, as this is called by multiple platforms.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
@@ -438,3 +439,4 @@ namespace AZ
|
||||
return component;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 "Budget.h"
|
||||
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(Animation);
|
||||
AZ_DEFINE_BUDGET(Audio);
|
||||
AZ_DEFINE_BUDGET(AzCore);
|
||||
AZ_DEFINE_BUDGET(Editor);
|
||||
AZ_DEFINE_BUDGET(Entity);
|
||||
AZ_DEFINE_BUDGET(Game);
|
||||
AZ_DEFINE_BUDGET(System);
|
||||
AZ_DEFINE_BUDGET(Physics);
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
struct BudgetImpl
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(BudgetImpl, AZ::SystemAllocator, 0);
|
||||
// TODO: Budget implementation for tracking budget wall time per-core, memory, etc.
|
||||
};
|
||||
|
||||
Budget::Budget(const char* name)
|
||||
: m_name{ name }
|
||||
, m_crc{ Crc32(name) }
|
||||
{
|
||||
}
|
||||
|
||||
Budget::Budget(const char* name, uint32_t crc)
|
||||
: m_name{ name }
|
||||
, m_crc{ crc }
|
||||
{
|
||||
m_impl = aznew BudgetImpl;
|
||||
}
|
||||
|
||||
Budget::~Budget()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:Budgets Methods below are stubbed pending future work to both update budget data and visualize it
|
||||
|
||||
void Budget::PerFrameReset()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::BeginProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::EndProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::TrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::UntrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// A budget collates per-frame resource utilization and memory for a particular category
|
||||
class Budget final
|
||||
{
|
||||
public:
|
||||
explicit Budget(const char* name);
|
||||
Budget(const char* name, uint32_t crc);
|
||||
~Budget();
|
||||
|
||||
void PerFrameReset();
|
||||
void BeginProfileRegion();
|
||||
void EndProfileRegion();
|
||||
void TrackAllocation(uint64_t bytes);
|
||||
void UntrackAllocation(uint64_t bytes);
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
uint32_t Crc() const
|
||||
{
|
||||
return m_crc;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* m_name;
|
||||
const uint32_t m_crc;
|
||||
struct BudgetImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
|
||||
// The budget is usable in the same file it was defined without needing an additional declaration.
|
||||
// If you encounter a linker error complaining that this function is not defined, you have likely forgotten to either
|
||||
// define or declare the budget used in a profile or memory marker. See AZ_DEFINE_BUDGET and AZ_DECLARE_BUDGET below
|
||||
// for usage.
|
||||
#define AZ_BUDGET_GETTER(name) GetAzBudget##name
|
||||
|
||||
#if defined(_RELEASE)
|
||||
#define AZ_DEFINE_BUDGET(name) \
|
||||
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
|
||||
{ \
|
||||
return nullptr; \
|
||||
}
|
||||
#else
|
||||
// Usage example:
|
||||
// In a single C++ source file:
|
||||
// AZ_DEFINE_BUDGET(AzCore);
|
||||
//
|
||||
// Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself)
|
||||
// AZ_DECLARE_BUDGET(AzCore);
|
||||
#define AZ_DEFINE_BUDGET(name) \
|
||||
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
|
||||
{ \
|
||||
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
|
||||
static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \
|
||||
return budget; \
|
||||
}
|
||||
#endif
|
||||
|
||||
// If using a budget defined in a different C++ source file, add AZ_DECLARE_BUDGET(yourBudget); somewhere in your source file at namespace
|
||||
// scope Alternatively, AZ_DECLARE_BUDGET can be used in a header to declare the budget for use across any users of the header
|
||||
#define AZ_DECLARE_BUDGET(name) ::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)()
|
||||
|
||||
// Declare budgets that are core engine budgets, or may be shared/needed across multiple external gems
|
||||
// You should NOT need to declare user-space or budgets with isolated usage here. Prefer declaring them local to the module(s) that use
|
||||
// the budget and defining them within a single module to avoid needing to recompile the entire engine.
|
||||
AZ_DECLARE_BUDGET(Animation);
|
||||
AZ_DECLARE_BUDGET(Audio);
|
||||
AZ_DECLARE_BUDGET(AzCore);
|
||||
AZ_DECLARE_BUDGET(Editor);
|
||||
AZ_DECLARE_BUDGET(Entity);
|
||||
AZ_DECLARE_BUDGET(Game);
|
||||
AZ_DECLARE_BUDGET(System);
|
||||
AZ_DECLARE_BUDGET(Physics);
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <AzCore/Debug/BudgetTracker.h>
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
constexpr static const char* BudgetTrackerEnvName = "budgetTrackerEnv";
|
||||
|
||||
struct BudgetTracker::BudgetTrackerImpl
|
||||
{
|
||||
AZStd::unordered_map<const char*, Budget> m_budgets;
|
||||
};
|
||||
|
||||
Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc)
|
||||
{
|
||||
BudgetTracker* tracker = Interface<BudgetTracker>::Get();
|
||||
if (tracker)
|
||||
{
|
||||
return &tracker->GetBudget(budgetName, crc);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BudgetTracker::~BudgetTracker()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool BudgetTracker::Init()
|
||||
{
|
||||
if (Interface<BudgetTracker>::Get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Interface<BudgetTracker>::Register(this);
|
||||
m_impl = new BudgetTrackerImpl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BudgetTracker::Reset()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
Interface<BudgetTracker>::Unregister(this);
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc)
|
||||
{
|
||||
AZStd::scoped_lock lock{ m_mutex };
|
||||
|
||||
auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 <AzCore/Module/Environment.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class Budget;
|
||||
|
||||
class BudgetTracker
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
|
||||
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
|
||||
|
||||
~BudgetTracker();
|
||||
|
||||
// Returns false if the budget tracker was already present in the environment (initialized already elsewhere)
|
||||
bool Init();
|
||||
void Reset();
|
||||
|
||||
Budget& GetBudget(const char* budgetName, uint32_t crc);
|
||||
|
||||
private:
|
||||
struct BudgetTrackerImpl;
|
||||
|
||||
AZStd::mutex m_mutex;
|
||||
|
||||
// The BudgetTracker is likely included in proportionally high number of files throughout the
|
||||
// engine, so indirection is used here to avoid imposing excessive recompilation in periods
|
||||
// while the budget system is iterated on.
|
||||
BudgetTrackerImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,63 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_H
|
||||
#define AZCORE_FRAME_PROFILER_H
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/std/containers/ring_buffer.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/parallel/config.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
namespace FrameProfiler
|
||||
{
|
||||
/**
|
||||
* This structure is used for frame data history, make sure it's memory efficient.
|
||||
*/
|
||||
struct FrameData
|
||||
{
|
||||
unsigned int m_frameId; ///< Id of the frame this data belongs to.
|
||||
union
|
||||
{
|
||||
ProfilerRegister::TimeData m_timeData;
|
||||
ProfilerRegister::ValuesData m_userValues;
|
||||
};
|
||||
};
|
||||
|
||||
struct RegisterData
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Profile register snapshot
|
||||
/// data that doesn't change
|
||||
const char* m_name; ///< Name of the profiler register.
|
||||
const char* m_function; ///< Function name in the code.
|
||||
int m_line; ///< Line number if the code.
|
||||
AZ::u32 m_systemId; ///< Register system id.
|
||||
ProfilerRegister::Type m_type;
|
||||
RegisterData* m_lastParent; ///< Pointer to the last parent register data.
|
||||
AZStd::ring_buffer<FrameData> m_frames; ///< History of all frame deltas (basically the data you want to display)
|
||||
};
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
typedef AZStd::unordered_map<const ProfilerRegister*, RegisterData> RegistersMap;
|
||||
AZStd::thread_id m_id; ///< Thread id (same as AZStd::thread::id)
|
||||
RegistersMap m_registers; ///< Map with all the registers (with history)
|
||||
};
|
||||
|
||||
typedef AZStd::fixed_vector<ThreadData, Profiler::m_maxNumberOfThreads> ThreadDataArray; ///< Array with samplers for all threads
|
||||
} // namespace FrameProfiler
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_H
|
||||
#pragma once
|
||||
@@ -1,38 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_BUS_H
|
||||
#define AZCORE_FRAME_PROFILER_BUS_H
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Debug/FrameProfiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class FrameProfilerComponent;
|
||||
|
||||
/**
|
||||
* Interface class for frame profiler events.
|
||||
*/
|
||||
class FrameProfilerEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~FrameProfilerEvents() {}
|
||||
|
||||
/// Called when the frame profiler has computed a new frame (even is there is no new data).
|
||||
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<FrameProfilerEvents> FrameProfilerBus;
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_BUS_H
|
||||
#pragma once
|
||||
@@ -1,250 +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 <AzCore/Debug/FrameProfilerComponent.h>
|
||||
#include <AzCore/Debug/FrameProfilerBus.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// FrameProfilerComponent
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
FrameProfilerComponent::FrameProfilerComponent()
|
||||
: m_numFramesStored(2)
|
||||
, m_frameId(0)
|
||||
, m_pauseOnFrame(0)
|
||||
, m_currentThreadData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~FrameProfilerComponent
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
FrameProfilerComponent::~FrameProfilerComponent()
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Activate
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Activate()
|
||||
{
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
Profiler::Create();
|
||||
}
|
||||
|
||||
Profiler::AddReference();
|
||||
|
||||
TickBus::Handler::BusConnect();
|
||||
AZ_Assert(m_numFramesStored >= 1, "We must have at least one frame to store, otherwise this component is useless!");
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Deactivate
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Deactivate()
|
||||
{
|
||||
TickBus::Handler::BusDisconnect();
|
||||
|
||||
Profiler::ReleaseReference();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnTick
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
(void)deltaTime;
|
||||
(void)time;
|
||||
++m_frameId;
|
||||
AZ_Error("Profiler", m_frameId != m_pauseOnFrame, "Triggered user pause/error on this frame! Check FrameProfilerComponent pauseOnFrame value!");
|
||||
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
return; // we can't sample registers without profiler
|
||||
}
|
||||
// collect data from the profiler
|
||||
m_currentThreadData = NULL;
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&FrameProfilerComponent::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2));
|
||||
|
||||
// process all the resulting data here, not while reading the registers
|
||||
for (size_t iThread = 0; iThread < m_threads.size(); ++iThread)
|
||||
{
|
||||
FrameProfiler::ThreadData& td = m_threads[iThread];
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator it = td.m_registers.begin();
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator last = td.m_registers.end();
|
||||
for (; it != last; ++it)
|
||||
{
|
||||
// fix up parents
|
||||
FrameProfiler::RegisterData& rd = it->second;
|
||||
if (rd.m_type == ProfilerRegister::PRT_TIME)
|
||||
{
|
||||
const FrameProfiler::FrameData& fd = rd.m_frames.back();
|
||||
if (fd.m_timeData.m_lastParent != nullptr)
|
||||
{
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator parentIt = td.m_registers.find(fd.m_timeData.m_lastParent);
|
||||
AZ_Assert(parentIt != td.m_registers.end(), "We have a parent register that is not in our register map. This should not happen!");
|
||||
rd.m_lastParent = &parentIt->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
rd.m_lastParent = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send an even to whomever cares
|
||||
EBUS_EVENT(FrameProfilerBus, OnFrameProfilerData, m_threads);
|
||||
}
|
||||
|
||||
int FrameProfilerComponent::GetTickOrder()
|
||||
{
|
||||
// Even it's not critical we should tick last to capture the current frame
|
||||
// so TICK_LAST (since it's not the last int +1 is a valid assumption)
|
||||
return TICK_LAST + 1;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReadRegisterCallback
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
bool FrameProfilerComponent::ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id)
|
||||
{
|
||||
if (m_currentThreadData == NULL || m_currentThreadData->m_id != id)
|
||||
{
|
||||
m_currentThreadData = NULL;
|
||||
|
||||
// find the thread and cache it, as we will received registers thread by thread... so we don't search.
|
||||
for (size_t i = 0; i < m_threads.size(); ++i)
|
||||
{
|
||||
FrameProfiler::ThreadData* td = &m_threads[i];
|
||||
if (td->m_id == id)
|
||||
{
|
||||
m_currentThreadData = td;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_currentThreadData == NULL)
|
||||
{
|
||||
m_threads.push_back();
|
||||
m_currentThreadData = &m_threads.back();
|
||||
m_currentThreadData->m_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
const ProfilerRegister* profReg = ®
|
||||
FrameProfiler::ThreadData::RegistersMap::pair_iter_bool pairIterBool = m_currentThreadData->m_registers.insert_key(profReg);
|
||||
FrameProfiler::RegisterData& regData = pairIterBool.first->second;
|
||||
|
||||
// now update dynamic data with as little as possible computation (we must be fast)
|
||||
FrameProfiler::FrameData fd; // we can actually move this computation (FrameData and push) for later but we will need to use more memory
|
||||
fd.m_frameId = m_frameId;
|
||||
|
||||
if (pairIterBool.second)
|
||||
{
|
||||
// when insert copy the static data only once
|
||||
regData.m_name = profReg->m_name;
|
||||
regData.m_function = profReg->m_function;
|
||||
regData.m_line = profReg->m_line;
|
||||
regData.m_systemId = profReg->m_systemId;
|
||||
regData.m_frames.set_capacity(m_numFramesStored);
|
||||
regData.m_type = static_cast<ProfilerRegister::Type>(profReg->m_type);
|
||||
}
|
||||
|
||||
switch (regData.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
fd.m_timeData.m_time = profReg->m_timeData.m_time;
|
||||
fd.m_timeData.m_childrenTime = profReg->m_timeData.m_childrenTime;
|
||||
fd.m_timeData.m_calls = profReg->m_timeData.m_calls;
|
||||
fd.m_timeData.m_childrenCalls = profReg->m_timeData.m_childrenCalls;
|
||||
fd.m_timeData.m_lastParent = profReg->m_timeData.m_lastParent;
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
fd.m_userValues.m_value1 = profReg->m_userValues.m_value1;
|
||||
fd.m_userValues.m_value2 = profReg->m_userValues.m_value2;
|
||||
fd.m_userValues.m_value3 = profReg->m_userValues.m_value3;
|
||||
fd.m_userValues.m_value4 = profReg->m_userValues.m_value4;
|
||||
fd.m_userValues.m_value5 = profReg->m_userValues.m_value5;
|
||||
} break;
|
||||
}
|
||||
|
||||
regData.m_frames.push_back(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetProvidedServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetIncompatibleServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetDependentServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC("MemoryService", 0x5c4d473c));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Reflect
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<FrameProfilerComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
->Field("numFramesStored", &FrameProfilerComponent::m_numFramesStored)
|
||||
->Field("pauseOnFrame", &FrameProfilerComponent::m_pauseOnFrame)
|
||||
;
|
||||
|
||||
if (EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<FrameProfilerComponent>(
|
||||
"Frame Profiler", "Performs per frame profiling (FPS counter, registers, etc.)")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_numFramesStored, "Number of Frames", "How many frames we will keep with the RUNTIME buffers.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 1)
|
||||
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_pauseOnFrame, "Pause on frame", "Paused the engine (debug break) on a specific frame. 0 means no pause!")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@@ -1,75 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
#define AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Debug/FrameProfiler.h>
|
||||
#include <AzCore/std/parallel/threadbus.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
/**
|
||||
* Frame profiler component provides a frame profiling information
|
||||
* (from FPS counter to profiler registers manipulation and so on).
|
||||
* It's a debug system so it should not be active in release
|
||||
*/
|
||||
class FrameProfilerComponent
|
||||
: public Component
|
||||
, public AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AZ::Debug::FrameProfilerComponent, "{B81739EF-ED77-4F67-9D05-6ADF94F0431A}")
|
||||
|
||||
FrameProfilerComponent();
|
||||
virtual ~FrameProfilerComponent();
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Component base
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Tick bus
|
||||
void OnTick(float deltaTime, ScriptTimePoint time) override;
|
||||
int GetTickOrder() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// \ref ComponentDescriptor::GetProvidedServices
|
||||
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
|
||||
/// \ref ComponentDescriptor::GetIncompatibleServices
|
||||
static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
/// \ref ComponentDescriptor::GetDependentServices
|
||||
static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
|
||||
/// \red ComponentDescriptor::Reflect
|
||||
static void Reflect(ReflectContext* reflection);
|
||||
|
||||
/// callback for reading profiler registers
|
||||
bool ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id);
|
||||
|
||||
// Keep in mind memory usage, increases quickly. Prefer remote tools (where the history is kept on the PC) instead of keeping long history
|
||||
unsigned int m_numFramesStored; ///< Number of frames that we will store in history buffers. >= 1
|
||||
unsigned int m_frameId; ///< Frame id (it's just counted from the start).
|
||||
|
||||
unsigned int m_pauseOnFrame; ///< Allows you to specify a frame the code will pause onto.
|
||||
|
||||
|
||||
FrameProfiler::ThreadDataArray m_threads; ///< Array with samplers for all threads
|
||||
FrameProfiler::ThreadData* m_currentThreadData; ///< Cached pointer to the last accessed thread data.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
#pragma once
|
||||
@@ -7,664 +7,4 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Debug/ProfilerDrillerBus.h>
|
||||
|
||||
#include <AzCore/std/containers/list.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/parallel/shared_spin_mutex.h>
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
uint32_t ProfileScope::GetSystemID(const char* system)
|
||||
{
|
||||
// TODO: stable ids for registered budgets
|
||||
return AZ::Crc32(system);
|
||||
}
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals
|
||||
AZStd::chrono::microseconds ProfilerRegister::TimeData::s_startStopOverheadPer1000Calls(0);
|
||||
Profiler* Profiler::s_instance = nullptr;
|
||||
u64 Profiler::s_id = 0;
|
||||
int Profiler::s_useCount = 0;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Profile data stored per thread.
|
||||
*/
|
||||
struct ProfilerThreadData
|
||||
{
|
||||
static const int m_maxStackSize = 32;
|
||||
typedef AZStd::list<ProfilerRegister, OSStdAllocator> ProfilerRegisterList;
|
||||
typedef AZStd::fixed_vector<ProfilerSection*, m_maxStackSize> ProfilerSectionStack;
|
||||
|
||||
AZStd::thread::id m_id; ///< Thread id.
|
||||
ProfilerRegisterList m_registers; ///< Thread profiler registers (for this thread).
|
||||
mutable AZStd::shared_spin_mutex m_registersLock; ///< Lock for accessing thread profiler entries. Sadly the only reason for this to exists is so we can read safe the register counters.
|
||||
ProfilerSectionStack m_stack; ///< Current active sections stack.
|
||||
};
|
||||
|
||||
struct ProfilerSystemData
|
||||
{
|
||||
AZ::u32 m_id;
|
||||
const char* m_name;
|
||||
bool m_isActive;
|
||||
};
|
||||
|
||||
/**
|
||||
* Profiler class data (hidden in from the header file)
|
||||
*/
|
||||
struct ProfilerData
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(ProfilerData, OSAllocator, 0);
|
||||
|
||||
AZStd::fixed_vector<ProfilerThreadData, Profiler::m_maxNumberOfThreads> m_threads; ///< Array with thread with all belonging information.
|
||||
AZStd::shared_spin_mutex m_threadDataMutex; ///< Spin read/write lock (shared_mutex) for access to the m_threads.
|
||||
AZStd::fixed_vector<ProfilerSystemData, Profiler::m_maxNumberOfSystems> m_systems; ///< Array with systems (profiler/timer groups) that you can enable/disable.
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
// Profiler
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
Profiler::Profiler(const Descriptor& desc)
|
||||
{
|
||||
(void)desc;
|
||||
m_data = aznew ProfilerData;
|
||||
|
||||
// we can periodically call this function (like the end of every frame to refresh the current estimation).
|
||||
ProfilerRegister::TimerComputeStartStopOverhead();
|
||||
|
||||
// use a timestamp as and id.
|
||||
s_id = AZStd::GetTimeUTCMilliSecond();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~Profiler
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
Profiler::~Profiler()
|
||||
{
|
||||
AZ_Assert(s_useCount == 0, "You deleted the profiler while it's still in use.");
|
||||
s_id = 0;
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Create
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
bool Profiler::Create(const Descriptor& desc)
|
||||
{
|
||||
AZ_Assert(s_instance == nullptr, "Profiler is already created!");
|
||||
if (s_instance != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
s_instance = azcreate(Profiler, (desc), AZ::OSAllocator, "Profiler", 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Destroy
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
void Profiler::Destroy()
|
||||
{
|
||||
AZ_Assert(s_instance != nullptr, "Profiler not created");
|
||||
if (s_instance)
|
||||
{
|
||||
azdestroy(s_instance, AZ::OSAllocator);
|
||||
s_instance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AddReference
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void Profiler::AddReference()
|
||||
{
|
||||
++s_useCount;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void Profiler::ReleaseReference()
|
||||
{
|
||||
AZ_Assert(s_useCount > 0, "Use count is already 0, you can't release it!");
|
||||
--s_useCount;
|
||||
if (s_useCount == 0)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterSystem
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
bool Profiler::RegisterSystem(AZ::u32 systemId, const char* name, bool isActive)
|
||||
{
|
||||
for (size_t i = 0; i < m_data->m_systems.size(); ++i)
|
||||
{
|
||||
if (m_data->m_systems[i].m_id == systemId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ProfilerSystemData sd;
|
||||
sd.m_id = systemId;
|
||||
sd.m_isActive = isActive;
|
||||
sd.m_name = name;
|
||||
m_data->m_systems.push_back(sd);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// UnregisterSystem
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
bool Profiler::UnregisterSystem(AZ::u32 systemId)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; i < m_data->m_systems.size(); ++i)
|
||||
{
|
||||
ProfilerSystemData& sd = m_data->m_systems[i];
|
||||
if (sd.m_id == systemId)
|
||||
{
|
||||
if (sd.m_isActive)
|
||||
{
|
||||
DeactivateSystem(sd.m_name);
|
||||
}
|
||||
// Make sure we triggest driller message when the m_threadDataMutex is NOT locked
|
||||
// as we lock them in reverse order when we update the profile driller.
|
||||
AZ_Assert(false, "Currently this code is unused. If we do use it, we should make call EBUS even outside of this function. Where m_threadDataMutex is NOT locked!");
|
||||
//EBUS_DBG_EVENT(ProfilerDrillerBus,OnUnregisterSystem,systemId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < m_data->m_systems.size())
|
||||
{
|
||||
m_data->m_systems.erase(m_data->m_systems.begin() + i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ActivateSystem
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
bool Profiler::SetSystemState(AZ::u32 systemId, bool isActive)
|
||||
{
|
||||
for (size_t i = 0; i < m_data->m_systems.size(); ++i)
|
||||
{
|
||||
ProfilerSystemData& sd = m_data->m_systems[i];
|
||||
if (sd.m_id == systemId)
|
||||
{
|
||||
if (sd.m_isActive != isActive)
|
||||
{
|
||||
sd.m_isActive = isActive;
|
||||
size_t numThreads = m_data->m_threads.size();
|
||||
for (size_t j = 0; j < numThreads; ++j)
|
||||
{
|
||||
ProfilerThreadData& data = m_data->m_threads[j];
|
||||
ProfilerThreadData::ProfilerRegisterList::iterator it = data.m_registers.begin();
|
||||
ProfilerThreadData::ProfilerRegisterList::iterator end = data.m_registers.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
ProfilerRegister& reg = *it;
|
||||
// This is a big question since this is the only writer
|
||||
// and the timers are readers and value should be read atomically (1 byte)
|
||||
// we should be safe without a synchronization here (as data should be written as we exit)
|
||||
// at worst we can put a volatile in front of the bool. Either way this should not cause
|
||||
// crashes or anything
|
||||
if (reg.m_systemId == systemId)
|
||||
{
|
||||
reg.m_isActive = isActive ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ActivateSystem
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void Profiler::ActivateSystem(const char* systemName)
|
||||
{
|
||||
AZ::u32 systemId = AZ::Crc32(systemName);
|
||||
bool isNewSystem = false;
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> writeLock(m_data->m_threadDataMutex);
|
||||
if (!SetSystemState(systemId, true))
|
||||
{
|
||||
// if the system is new add it
|
||||
RegisterSystem(systemId, systemName, true);
|
||||
isNewSystem = true;
|
||||
}
|
||||
}
|
||||
if (isNewSystem)
|
||||
{
|
||||
// Make sure we triggest driller message when the m_threadDataMutex is NOT locked
|
||||
// as we lock them in reverse order when we update the profile driller.
|
||||
EBUS_DBG_EVENT(ProfilerDrillerBus, OnRegisterSystem, systemId, systemName);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DeactivateSystem
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void Profiler::DeactivateSystem(const char* systemName)
|
||||
{
|
||||
AZ::u32 systemId = AZ::Crc32(systemName);
|
||||
bool isNewSystem = false;
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> writeLock(m_data->m_threadDataMutex);
|
||||
if (!SetSystemState(systemId, false))
|
||||
{
|
||||
// if the system is new add it
|
||||
RegisterSystem(systemId, systemName, false);
|
||||
isNewSystem = true;
|
||||
}
|
||||
}
|
||||
if (isNewSystem)
|
||||
{
|
||||
// Make sure we triggest driller message when the m_threadDataMutex is NOT locked
|
||||
// as we lock them in reverse order when we update the profile driller.
|
||||
EBUS_DBG_EVENT(ProfilerDrillerBus, OnRegisterSystem, systemId, systemName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// IsSystemActive
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
bool Profiler::IsSystemActive(const char* systemName) const
|
||||
{
|
||||
return IsSystemActive(AZ::Crc32(systemName));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// IsSystemActive
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
bool Profiler::IsSystemActive(AZ::u32 systemId) const
|
||||
{
|
||||
for (size_t i = 0; i < m_data->m_systems.size(); ++i)
|
||||
{
|
||||
if (m_data->m_systems[i].m_id == systemId)
|
||||
{
|
||||
return m_data->m_systems[i].m_isActive != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetNumberOfSystems
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
int Profiler::GetNumberOfSystems() const
|
||||
{
|
||||
return static_cast<int>(m_data->m_systems.size());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetSystemName
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
const char* Profiler::GetSystemName(int index) const
|
||||
{
|
||||
return m_data->m_systems[index].m_name;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetSystemName
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
const char* Profiler::GetSystemName(AZ::u32 systemId) const
|
||||
{
|
||||
for (size_t i = 0; i < m_data->m_systems.size(); ++i)
|
||||
{
|
||||
if (m_data->m_systems[i].m_id == systemId)
|
||||
{
|
||||
return m_data->m_systems[i].m_name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RemoveThreadData
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
void Profiler::RemoveThreadData(AZStd::thread_id id)
|
||||
{
|
||||
// this is very tricky we must be sure that thread is no longer operational
|
||||
// otherwise we will crash badly. We can do only because nobody should
|
||||
// reference this registers but the thread local data.
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> writeLock(m_data->m_threadDataMutex);
|
||||
size_t numThreads = m_data->m_threads.size();
|
||||
ProfilerThreadData* threadData = NULL;
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
ProfilerThreadData& data = m_data->m_threads[i];
|
||||
if (data.m_id == id)
|
||||
{
|
||||
threadData = &data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (threadData)
|
||||
{
|
||||
// delete all registers, we can remove the thread data too, but we will need to switch the structure to list
|
||||
// so far this is super minimal overhead, registers are more.
|
||||
threadData->m_registers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReadRegisterValues
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
void Profiler::ReadRegisterValues(const ReadProfileRegisterCB& callback, AZ::u32 systemFilter, const AZStd::thread_id* threadFilter) const
|
||||
{
|
||||
AZStd::shared_lock<AZStd::shared_spin_mutex> readLock(s_instance->m_data->m_threadDataMutex);
|
||||
size_t numThreads = Profiler::s_instance->m_data->m_threads.size();
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
const ProfilerThreadData& data = s_instance->m_data->m_threads[i];
|
||||
if (threadFilter && *threadFilter != data.m_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
{
|
||||
AZStd::shared_lock<AZStd::shared_spin_mutex> registersLock(data.m_registersLock);
|
||||
ProfilerThreadData::ProfilerRegisterList::const_iterator it = data.m_registers.begin();
|
||||
ProfilerThreadData::ProfilerRegisterList::const_iterator end = data.m_registers.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
const ProfilerRegister& reg = *it;
|
||||
if (!reg.m_isActive || (systemFilter != 0 && systemFilter != reg.m_systemId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!callback(reg, data.m_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResetRegisters
|
||||
// [12/4/2012]
|
||||
//=========================================================================
|
||||
void Profiler::ResetRegisters()
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> writeLock(s_instance->m_data->m_threadDataMutex);
|
||||
size_t numThreads = Profiler::s_instance->m_data->m_threads.size();
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
ProfilerThreadData& data = s_instance->m_data->m_threads[i];
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> registersLock(data.m_registersLock);
|
||||
ProfilerThreadData::ProfilerRegisterList::iterator it = data.m_registers.begin();
|
||||
ProfilerThreadData::ProfilerRegisterList::iterator end = data.m_registers.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
ProfilerRegister& reg = *it;
|
||||
reg.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset registers event
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CreateRegister
|
||||
// [6/28/2013]
|
||||
//=========================================================================
|
||||
ProfilerRegister*
|
||||
ProfilerRegister::CreateRegister(const char* systemName, const char* name, const char* function, int line, ProfilerRegister::Type type)
|
||||
{
|
||||
static AZ_THREAD_LOCAL ProfilerThreadData* threadData = nullptr;
|
||||
static AZ_THREAD_LOCAL u64 profilerId = 0;
|
||||
if (profilerId != Profiler::s_id)
|
||||
{
|
||||
threadData = nullptr; // profiler has changed
|
||||
profilerId = Profiler::s_id;
|
||||
}
|
||||
AZ::u32 systemId = AZ::Crc32(systemName);
|
||||
ProfilerRegister* reg;
|
||||
{
|
||||
AZStd::unique_lock<AZStd::shared_spin_mutex> writeLock(Profiler::s_instance->m_data->m_threadDataMutex);
|
||||
|
||||
// make sure we have the system registered. This function will just return false if the system exists.
|
||||
if (systemName)
|
||||
{
|
||||
Profiler::s_instance->RegisterSystem(systemId, systemName, true);
|
||||
}
|
||||
|
||||
if (threadData == nullptr) // if this is a new thread add the data
|
||||
{
|
||||
AZStd::thread::id threadId = AZStd::this_thread::get_id();
|
||||
Profiler::s_instance->m_data->m_threads.push_back();
|
||||
threadData = &Profiler::s_instance->m_data->m_threads.back();
|
||||
threadData->m_id = threadId;
|
||||
}
|
||||
threadData->m_registers.push_back();
|
||||
reg = &threadData->m_registers.back();
|
||||
reg->m_name = name;
|
||||
reg->m_function = function;
|
||||
reg->m_line = line;
|
||||
reg->m_systemId = systemId;
|
||||
reg->m_isActive = Profiler::s_instance->IsSystemActive(systemId) ? 1 : 0;
|
||||
reg->m_type = type;
|
||||
reg->m_threadData = threadData;
|
||||
|
||||
reg->Reset();
|
||||
}
|
||||
// Make sure we triggest driller message when the m_threadDataMutex is NOT locked
|
||||
// as we lock them in reverse order when we update the profile driller.
|
||||
EBUS_DBG_EVENT(ProfilerDrillerBus, OnNewRegister, *reg, threadData->m_id);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// TimerCreateAndStart
|
||||
// [11/30/2012]
|
||||
//=========================================================================
|
||||
ProfilerRegister*
|
||||
ProfilerRegister::TimerCreateAndStart(const char* systemName, const char* name, ProfilerSection * section, const char* function, int line)
|
||||
{
|
||||
AZStd::chrono::system_clock::time_point start = AZStd::chrono::system_clock::now();
|
||||
ProfilerRegister* reg = CreateRegister(systemName, name, function, line, ProfilerRegister::PRT_TIME);
|
||||
AZStd::chrono::system_clock::time_point end = AZStd::chrono::system_clock::now();
|
||||
|
||||
// adjust the parent timer with the overhead we incur during timer operations. (TODO with TLS this is so fast that we might not need to do it)
|
||||
if (!reg->m_threadData->m_stack.empty()) // if we are not he last element
|
||||
{
|
||||
AZStd::chrono::microseconds elapsed = end - start;
|
||||
reg->m_threadData->m_stack.back()->m_childTime += elapsed; // no need to check if we go in the future as this will happen on Stop
|
||||
}
|
||||
|
||||
if (reg->m_isActive)
|
||||
{
|
||||
section->m_register = reg;
|
||||
section->m_start = end;
|
||||
reg->m_threadData->m_stack.push_back(section);
|
||||
}
|
||||
else
|
||||
{
|
||||
section->m_register = nullptr;
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ValueCreate
|
||||
// [6/28/2013]
|
||||
//=========================================================================
|
||||
ProfilerRegister*
|
||||
ProfilerRegister::ValueCreate(const char* systemName, const char* name, const char* function, int line)
|
||||
{
|
||||
return CreateRegister(systemName, name, function, line, ProfilerRegister::PRT_VALUE);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// TimerStart
|
||||
// [11/29/2012]
|
||||
//=========================================================================
|
||||
void ProfilerRegister::TimerStart(ProfilerSection* section)
|
||||
{
|
||||
ProfilerRegister* reg = this;
|
||||
|
||||
if (reg->m_isActive)
|
||||
{
|
||||
section->m_register = reg;
|
||||
reg->m_threadData->m_stack.push_back(section);
|
||||
section->m_start = AZStd::chrono::system_clock::now();
|
||||
}
|
||||
else
|
||||
{
|
||||
section->m_register = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// TimerStop
|
||||
// [11/29/2012]
|
||||
//=========================================================================
|
||||
void ProfilerRegister::TimerStop()
|
||||
{
|
||||
AZStd::chrono::system_clock::time_point end = AZStd::chrono::system_clock::now();
|
||||
ProfilerSection* section = m_threadData->m_stack.back();
|
||||
AZStd::chrono::microseconds elapsedTime = end - section->m_start;
|
||||
{
|
||||
m_threadData->m_registersLock.lock(); // lock for write
|
||||
++m_timeData.m_calls;
|
||||
m_timeData.m_time += elapsedTime.count();
|
||||
m_timeData.m_childrenTime += section->m_childTime.count();
|
||||
m_timeData.m_childrenCalls += section->m_childCalls;
|
||||
m_threadData->m_registersLock.unlock(); // unlock
|
||||
}
|
||||
m_threadData->m_stack.pop_back();
|
||||
|
||||
// adjust the parent timer with the overhead we incur during timer operations.
|
||||
if (!m_threadData->m_stack.empty())
|
||||
{
|
||||
ProfilerSection* parent = m_threadData->m_stack.back();
|
||||
m_timeData.m_lastParent = parent->m_register;
|
||||
parent->m_childTime += elapsedTime /*+ s_startStopOverhead*/; // add the overhead since most of it is in Stop()
|
||||
++parent->m_childCalls;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Reset
|
||||
// [12/4/2012]
|
||||
//=========================================================================
|
||||
void ProfilerRegister::Reset()
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case PRT_TIME:
|
||||
{
|
||||
m_timeData.m_time = 0;
|
||||
m_timeData.m_childrenTime = 0;
|
||||
m_timeData.m_calls = 0;
|
||||
m_timeData.m_childrenCalls = 0;
|
||||
m_timeData.m_lastParent = nullptr;
|
||||
} break;
|
||||
case PRT_VALUE:
|
||||
{
|
||||
m_userValues.m_value1 = 0;
|
||||
m_userValues.m_value2 = 0;
|
||||
m_userValues.m_value3 = 0;
|
||||
m_userValues.m_value4 = 0;
|
||||
m_userValues.m_value5 = 0;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ComputeStartStopOverhead
|
||||
// [12/3/2012]
|
||||
//=========================================================================
|
||||
void ProfilerRegister::TimerComputeStartStopOverhead()
|
||||
{
|
||||
// compute default thread start stop overhead
|
||||
ProfilerThreadData sampleThreadData;
|
||||
sampleThreadData.m_id = AZStd::this_thread::get_id();
|
||||
sampleThreadData.m_registers.push_back();
|
||||
ProfilerRegister& sampleRegister = sampleThreadData.m_registers.back();
|
||||
sampleRegister.m_isActive = true;
|
||||
sampleRegister.m_name = nullptr;
|
||||
sampleRegister.m_systemId = 0;
|
||||
sampleRegister.m_threadData = &sampleThreadData;
|
||||
|
||||
const int numSamples = 1000;
|
||||
for (int iRepetition = 0; iRepetition < 1000; ++iRepetition) // just for test
|
||||
{
|
||||
ProfilerSection section;
|
||||
sampleRegister.TimerStart(§ion);
|
||||
AZStd::chrono::system_clock::time_point start = AZStd::chrono::system_clock::now();
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
static AZ::Debug::ProfilerRegister* sampleRegisterPtr = &sampleRegister; // the creation is timed differently
|
||||
ProfilerSection subSection;
|
||||
if (sampleRegisterPtr != NULL)
|
||||
{
|
||||
sampleRegister.TimerStart(&subSection);
|
||||
}
|
||||
}
|
||||
AZStd::chrono::microseconds elapsed = (AZStd::chrono::system_clock::now() - start);
|
||||
if (TimeData::s_startStopOverheadPer1000Calls.count() == 0) // if first time set otherwise smooth average
|
||||
{
|
||||
TimeData::s_startStopOverheadPer1000Calls = elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
float fNew = static_cast<float>(elapsed.count());
|
||||
float fCurrent = static_cast<float>(TimeData::s_startStopOverheadPer1000Calls.count());
|
||||
int deltaValue = static_cast<int>((fNew - fCurrent) * 0.1f);
|
||||
if (deltaValue < 0)
|
||||
{
|
||||
TimeData::s_startStopOverheadPer1000Calls -= AZStd::chrono::microseconds(-deltaValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeData::s_startStopOverheadPer1000Calls += AZStd::chrono::microseconds(deltaValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
//AZ_TracePrintf("Profiler","Overhead %d microseconds per 1000 profile calls!\n",TimeData::s_startStopOverheadPer1000Calls.count());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -7,42 +7,49 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
|
||||
#ifdef USE_PIX
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <WinPixEventRuntime/pix3.h>
|
||||
#endif
|
||||
|
||||
#if defined(AZ_PROFILER_MACRO_DISABLE) // by default we never disable the profiler registers as their overhead should be minimal, you can still do that for your code though.
|
||||
# define AZ_PROFILE_SCOPE(...)
|
||||
# define AZ_PROFILE_FUNCTION(...)
|
||||
# define AZ_PROFILE_BEGIN(...)
|
||||
# define AZ_PROFILE_END(...)
|
||||
#if defined(AZ_PROFILER_MACRO_DISABLE) // by default we never disable the profiler registers as their overhead should be minimal, you can
|
||||
// still do that for your code though.
|
||||
#define AZ_PROFILE_SCOPE(...)
|
||||
#define AZ_PROFILE_FUNCTION(...)
|
||||
#define AZ_PROFILE_BEGIN(...)
|
||||
#define AZ_PROFILE_END(...)
|
||||
#else
|
||||
|
||||
/**
|
||||
* Macro to declare a profile section for the current scope { }.
|
||||
* format is: AZ_PROFILE_SCOPE(categoryName, const char* formatStr, ...)
|
||||
*/
|
||||
# define AZ_PROFILE_SCOPE(category, ...) ::AZ::ProfileScope AZ_JOIN(azProfileScope, __LINE__){ #category, __VA_ARGS__ }
|
||||
# define AZ_PROFILE_FUNCTION(category) AZ_PROFILE_SCOPE(category, AZ_FUNCTION_SIGNATURE)
|
||||
#define AZ_PROFILE_SCOPE(budget, ...) \
|
||||
::AZ::Debug::ProfileScope AZ_JOIN(azProfileScope, __LINE__) \
|
||||
{ \
|
||||
AZ_BUDGET_GETTER(budget)(), __VA_ARGS__ \
|
||||
}
|
||||
|
||||
#define AZ_PROFILE_FUNCTION(category) AZ_PROFILE_SCOPE(category, AZ_FUNCTION_SIGNATURE)
|
||||
|
||||
// Prefer using the scoped macros which automatically end the event (AZ_PROFILE_SCOPE/AZ_PROFILE_FUNCTION)
|
||||
# define AZ_PROFILE_BEGIN(category, ...) ::AZ::ProfileScope::BeginRegion(#category, __VA_ARGS__)
|
||||
# define AZ_PROFILE_END() ::AZ::ProfileScope::EndRegion()
|
||||
#define AZ_PROFILE_BEGIN(budget, ...) ::AZ::Debug::ProfileScope::BeginRegion(AZ_BUDGET_GETTER(budget)(), __VA_ARGS__)
|
||||
#define AZ_PROFILE_END(budget) ::AZ::Debug::ProfileScope::EndRegion(AZ_BUDGET_GETTER(budget)())
|
||||
|
||||
#endif // AZ_PROFILER_MACRO_DISABLE
|
||||
|
||||
#ifndef AZ_PROFILE_INTERVAL_START
|
||||
# define AZ_PROFILE_INTERVAL_START(...)
|
||||
# define AZ_PROFILE_INTERVAL_START_COLORED(...)
|
||||
# define AZ_PROFILE_INTERVAL_END(...)
|
||||
# define AZ_PROFILE_INTERVAL_SCOPED(...)
|
||||
#define AZ_PROFILE_INTERVAL_START(...)
|
||||
#define AZ_PROFILE_INTERVAL_START_COLORED(...)
|
||||
#define AZ_PROFILE_INTERVAL_END(...)
|
||||
#define AZ_PROFILE_INTERVAL_SCOPED(...)
|
||||
#endif
|
||||
|
||||
#ifndef AZ_PROFILE_DATAPOINT
|
||||
# define AZ_PROFILE_DATAPOINT(...)
|
||||
# define AZ_PROFILE_DATAPOINT_PERCENT(...)
|
||||
#define AZ_PROFILE_DATAPOINT(...)
|
||||
#define AZ_PROFILE_DATAPOINT_PERCENT(...)
|
||||
#endif
|
||||
|
||||
namespace AZStd
|
||||
@@ -50,340 +57,25 @@ namespace AZStd
|
||||
struct thread_id; // forward declare. This is the same type as AZStd::thread::id
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class ProfileScope
|
||||
{
|
||||
public:
|
||||
static uint32_t GetSystemID(const char* system);
|
||||
template<typename... T>
|
||||
static void BeginRegion([[maybe_unused]] Budget* budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args);
|
||||
|
||||
static void EndRegion([[maybe_unused]] Budget* budget);
|
||||
|
||||
template<typename... T>
|
||||
static void BeginRegion([[maybe_unused]] const char* system, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
{
|
||||
// TODO: Verification that the supplied system name corresponds to a known budget
|
||||
#if defined(USE_PIX)
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(GetSystemID(system) & 0xff), eventName, args...);
|
||||
#endif
|
||||
// TODO: injecting instrumentation for other profilers
|
||||
// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
|
||||
// will be introduced in a future PR
|
||||
}
|
||||
ProfileScope(Budget* budget, char const* eventName, T const&... args);
|
||||
|
||||
static void EndRegion()
|
||||
{
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
}
|
||||
~ProfileScope();
|
||||
|
||||
template<typename... T>
|
||||
ProfileScope(const char* system, char const* eventName, T const&... args)
|
||||
{
|
||||
BeginRegion(system, eventName, args...);
|
||||
}
|
||||
|
||||
~ProfileScope()
|
||||
{
|
||||
EndRegion();
|
||||
}
|
||||
private:
|
||||
Budget* m_budget;
|
||||
};
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
class ProfilerSection;
|
||||
class ProfilerRegister;
|
||||
struct ProfilerThreadData;
|
||||
struct ProfilerData;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Profiler
|
||||
{
|
||||
friend class ProfilerRegister;
|
||||
friend struct ProfilerData;
|
||||
public:
|
||||
/// Max number of threads supported by the profiler.
|
||||
static const int m_maxNumberOfThreads = 32;
|
||||
/// Max number of systems supported by the profiler. (We can switch this container if needed)
|
||||
static const int m_maxNumberOfSystems = 64;
|
||||
|
||||
~Profiler();
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
};
|
||||
|
||||
static bool Create(const Descriptor& desc = Descriptor());
|
||||
static void Destroy();
|
||||
static bool IsReady() { return s_instance != NULL; }
|
||||
static Profiler& Instance() { return *s_instance; }
|
||||
static u64 GetId() { return s_id; }
|
||||
|
||||
/// Increment the use count.
|
||||
static void AddReference();
|
||||
/// Release the use count if 0 a Destroy will be called automatically.
|
||||
static void ReleaseReference();
|
||||
|
||||
void ActivateSystem(const char* systemName);
|
||||
void DeactivateSystem(const char* systemName);
|
||||
bool IsSystemActive(const char* systemName) const;
|
||||
bool IsSystemActive(AZ::u32 systemId) const;
|
||||
int GetNumberOfSystems() const;
|
||||
const char* GetSystemName(int index) const;
|
||||
const char* GetSystemName(AZ::u32 systemId) const;
|
||||
|
||||
/** Callback to read a single register. Make sure you read the data as fast as possible. Don't compute inside the callback
|
||||
* it will lock and hold all the registers that we process. The best is just to read the value and push it into a
|
||||
* history buffer.
|
||||
*/
|
||||
typedef AZStd::function<bool (const ProfilerRegister&, const AZStd::thread_id&)> ReadProfileRegisterCB;
|
||||
/**
|
||||
* Read register values, make sure the code here is fast and efficient as we are holding a lock.
|
||||
* provide a callback that will be called for each register.
|
||||
* You can choose to filter your values by thread or a system. Use this filter only to narrow you samples. Don't
|
||||
* use it for multiple calls to sort your counters, use the history data.
|
||||
* It addition keep in mind that you can run this function is parallel, as we only read the values.
|
||||
*/
|
||||
void ReadRegisterValues(const ReadProfileRegisterCB& callback, AZ::u32 systemFilter = 0, const AZStd::thread_id* threadFilter = NULL) const;
|
||||
/**
|
||||
* This is slow operation that will cause contention try to avoid using it. A better way will be each frame instead of reset to read and store
|
||||
* register values (this is good for history too) and make the difference that way.
|
||||
*/
|
||||
void ResetRegisters();
|
||||
|
||||
/// You can remove thread data ONLY IF YOU ARE SURE THIS THREAD IS NO LONGER ACTIVE! This will work only is specific cases.
|
||||
void RemoveThreadData(AZStd::thread_id id);
|
||||
|
||||
private:
|
||||
/// Register a new system in the profiler. Make sure the proper locks are LOCKED when calling this function (m_threadDataMutex)
|
||||
bool RegisterSystem(AZ::u32 systemId, const char* name, bool isActive);
|
||||
/// Unregister a system. Make sure the proper locks are LOCKED when calling this function (m_threadDataMutex)
|
||||
bool UnregisterSystem(AZ::u32 systemId);
|
||||
/// Sets the system active/inactive state. Make sure the proper locks are LOCKED when calling this function (m_threadDataMutex)
|
||||
bool SetSystemState(AZ::u32 systemId, bool isActive);
|
||||
|
||||
Profiler(const Descriptor& desc);
|
||||
Profiler& operator=(const Profiler&);
|
||||
|
||||
ProfilerData* m_data; ///< Hidden data to reduce the number of header files included;
|
||||
static Profiler* s_instance; ///< The only instance of the profiler.
|
||||
static u64 s_id; ///< Profiler unique (over time) id (don't use the pointer as it might be reused).
|
||||
static int s_useCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* A profiler "virtual" register that contains data about a certain place in the code.
|
||||
*/
|
||||
class ProfilerRegister
|
||||
{
|
||||
friend class Profiler;
|
||||
public:
|
||||
ProfilerRegister()
|
||||
{}
|
||||
|
||||
enum Type
|
||||
{
|
||||
PRT_TIME = 0, ///< Time (members m_time,m_childrenTime,m_calls, m_childrenCalls and m_lastParant are used) register.
|
||||
PRT_VALUE, ///< Value register
|
||||
};
|
||||
|
||||
/// Time register data.
|
||||
struct TimeData
|
||||
{
|
||||
AZ::u64 m_time; ///< Total inclusive time current and children in microseconds.
|
||||
AZ::u64 m_childrenTime; ///< Time taken by child profilers in microseconds.
|
||||
AZ::s64 m_calls; ///< Number of calls for this register.
|
||||
AZ::s64 m_childrenCalls;///< Number of children calls.
|
||||
ProfilerRegister* m_lastParent; ///< Pointer to the last parent register.
|
||||
|
||||
static AZStd::chrono::microseconds s_startStopOverheadPer1000Calls; ///< Static constant representing a standard start stop overhead per 1000 calls. You can use this to adjust timings.
|
||||
};
|
||||
|
||||
/// Value register data.
|
||||
struct ValuesData
|
||||
{
|
||||
AZ::s64 m_value1;
|
||||
AZ::s64 m_value2;
|
||||
AZ::s64 m_value3;
|
||||
AZ::s64 m_value4;
|
||||
AZ::s64 m_value5;
|
||||
};
|
||||
|
||||
static ProfilerRegister* TimerCreateAndStart(const char* systemName, const char* name, ProfilerSection* section, const char* function, int line);
|
||||
static ProfilerRegister* ValueCreate(const char* systemName, const char* name, const char* function, int line);
|
||||
void TimerStart(ProfilerSection* section);
|
||||
|
||||
void ValueSet(const AZ::s64& v1);
|
||||
void ValueSet(const AZ::s64& v1, const AZ::s64& v2);
|
||||
void ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3);
|
||||
void ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4);
|
||||
void ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4, const AZ::s64& v5);
|
||||
|
||||
void ValueAdd(const AZ::s64& v1);
|
||||
void ValueAdd(const AZ::s64& v1, const AZ::s64& v2);
|
||||
void ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3);
|
||||
void ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4);
|
||||
void ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4, const AZ::s64& v5);
|
||||
|
||||
// Dynamic register data
|
||||
union
|
||||
{
|
||||
TimeData m_timeData;
|
||||
ValuesData m_userValues;
|
||||
};
|
||||
|
||||
// Static value data.
|
||||
const char* m_name; ///< Name of the profiler register.
|
||||
const char* m_function; ///< Function name in the code.
|
||||
int m_line; ///< Line number if the code.
|
||||
AZ::u32 m_systemId; ///< ID of the system this profiler belongs to.
|
||||
unsigned char m_type : 7; ///< Register type
|
||||
unsigned char m_isActive : 1; ///< Flag if the profiler is active.
|
||||
|
||||
private:
|
||||
friend class ProfilerSection;
|
||||
|
||||
static ProfilerRegister* CreateRegister(const char* systemName, const char* name, const char* function, int line, ProfilerRegister::Type type);
|
||||
|
||||
/// Compute static start/stop overhead approximation. You can call this periodically (or not) to update the overhead.
|
||||
static void TimerComputeStartStopOverhead();
|
||||
|
||||
void TimerStop();
|
||||
|
||||
void Reset();
|
||||
|
||||
ProfilerRegister* GetValueRegisterForThisThread();
|
||||
|
||||
ProfilerThreadData* m_threadData; ///< Pointer to this entry thread data.
|
||||
};
|
||||
|
||||
/**
|
||||
* Scoped stop register count on destruction.
|
||||
*/
|
||||
class ProfilerSection
|
||||
{
|
||||
friend class ProfilerRegister;
|
||||
public:
|
||||
ProfilerSection()
|
||||
: m_register(nullptr)
|
||||
, m_profilerId(AZ::Debug::Profiler::GetId())
|
||||
, m_childTime(0)
|
||||
, m_childCalls(0)
|
||||
{}
|
||||
|
||||
~ProfilerSection()
|
||||
{
|
||||
// If we have a valid register and the profiler did not change while we were active stop the register.
|
||||
if (m_register && m_profilerId == AZ::Debug::Profiler::GetId())
|
||||
{
|
||||
m_register->TimerStop();
|
||||
}
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
// If we have a valid register and the profiler did not change while we were active stop the register.
|
||||
if (m_register && m_profilerId == AZ::Debug::Profiler::GetId())
|
||||
{
|
||||
m_register->TimerStop();
|
||||
}
|
||||
m_register = nullptr;
|
||||
}
|
||||
private:
|
||||
ProfilerRegister* m_register; ///< Pointer to the owning profiler register.
|
||||
u64 m_profilerId; ///< Id of the profiler when we started this section.
|
||||
AZStd::chrono::system_clock::time_point m_start; ///< Start mark.
|
||||
AZStd::chrono::microseconds m_childTime; ///< Time spent in child profilers.
|
||||
int m_childCalls; ///< Number of children calls.
|
||||
};
|
||||
|
||||
AZ_FORCE_INLINE ProfilerRegister* ProfilerRegister::GetValueRegisterForThisThread()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueSet(const AZ::s64& v1)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 = v1;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueSet(const AZ::s64& v1, const AZ::s64& v2)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 = v1;
|
||||
reg->m_userValues.m_value2 = v2;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 = v1;
|
||||
reg->m_userValues.m_value2 = v2;
|
||||
reg->m_userValues.m_value3 = v3;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 = v1;
|
||||
reg->m_userValues.m_value2 = v2;
|
||||
reg->m_userValues.m_value3 = v3;
|
||||
reg->m_userValues.m_value4 = v4;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueSet(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4, const AZ::s64& v5)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 = v1;
|
||||
reg->m_userValues.m_value2 = v2;
|
||||
reg->m_userValues.m_value3 = v3;
|
||||
reg->m_userValues.m_value4 = v4;
|
||||
reg->m_userValues.m_value5 = v5;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueAdd(const AZ::s64& v1)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 += v1;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueAdd(const AZ::s64& v1, const AZ::s64& v2)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 += v1;
|
||||
reg->m_userValues.m_value2 += v2;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 += v1;
|
||||
reg->m_userValues.m_value2 += v2;
|
||||
reg->m_userValues.m_value3 += v3;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 += v1;
|
||||
reg->m_userValues.m_value2 += v2;
|
||||
reg->m_userValues.m_value3 += v3;
|
||||
reg->m_userValues.m_value4 += v4;
|
||||
}
|
||||
AZ_FORCE_INLINE void ProfilerRegister::ValueAdd(const AZ::s64& v1, const AZ::s64& v2, const AZ::s64& v3, const AZ::s64& v4, const AZ::s64& v5)
|
||||
{
|
||||
ProfilerRegister* reg = GetValueRegisterForThisThread();
|
||||
reg->m_userValues.m_value1 += v1;
|
||||
reg->m_userValues.m_value2 += v2;
|
||||
reg->m_userValues.m_value3 += v3;
|
||||
reg->m_userValues.m_value4 += v4;
|
||||
reg->m_userValues.m_value5 += v5;
|
||||
}
|
||||
} // namespace Debug
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
struct RegisterData
|
||||
{
|
||||
AZ::Debug::ProfilerRegister* m_register; ///< Pointer to the register data.
|
||||
AZ::u64 m_profilerId; ///< Profiler ID which create the \ref register data.
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
} // namespace AZ::Debug
|
||||
|
||||
#ifdef USE_PIX
|
||||
// The pix3 header unfortunately brings in other Windows macros we need to undef
|
||||
@@ -391,3 +83,5 @@ namespace AZ
|
||||
#undef LoadImage
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <AzCore/Debug/Profiler.inl>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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::Debug
|
||||
{
|
||||
template<typename... T>
|
||||
void ProfileScope::BeginRegion(
|
||||
[[maybe_unused]] Budget* budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
{
|
||||
if (!budget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
// TODO: Verification that the supplied system name corresponds to a known budget
|
||||
#if defined(USE_PIX)
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
|
||||
#endif
|
||||
budget->BeginProfileRegion();
|
||||
// TODO: injecting instrumentation for other profilers
|
||||
// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
|
||||
// will be introduced in a future PR
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ProfileScope::EndRegion([[maybe_unused]] Budget* budget)
|
||||
{
|
||||
if (!budget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
budget->EndProfileRegion();
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
ProfileScope::ProfileScope(Budget* budget, char const* eventName, T const&... args)
|
||||
: m_budget{ budget }
|
||||
{
|
||||
BeginRegion(budget, eventName, args...);
|
||||
}
|
||||
|
||||
inline ProfileScope::~ProfileScope()
|
||||
{
|
||||
EndRegion(m_budget);
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
@@ -1,310 +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 <AzCore/Debug/ProfilerDriller.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/bind/bind.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// ProfilerDriller
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
ProfilerDriller::ProfilerDriller()
|
||||
{
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~ProfilerDriller
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
ProfilerDriller::~ProfilerDriller()
|
||||
{
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Start
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Start(const Param* params, int numParams)
|
||||
{
|
||||
for (int i = 0; i < m_numberOfSystemFilters; ++i)
|
||||
{
|
||||
m_systemFilters[i].desc = "SystemID of the system which counters we are interested in";
|
||||
m_systemFilters[i].type = Param::PT_INT;
|
||||
m_systemFilters[i].value = 0;
|
||||
}
|
||||
|
||||
// Copy valid filters.
|
||||
m_numberOfValidFilters = 0;
|
||||
if (params)
|
||||
{
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
{
|
||||
if (params[i].type == Param::PT_INT && params[i].value != 0)
|
||||
{
|
||||
m_systemFilters[m_numberOfValidFilters++].value = params[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// output current threads
|
||||
for (ThreadArrayType::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
OutputThreadEnter(*it);
|
||||
}
|
||||
|
||||
ProfilerDrillerBus::Handler::BusConnect();
|
||||
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
Profiler::Create();
|
||||
}
|
||||
|
||||
Profiler::AddReference();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Stop
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Stop()
|
||||
{
|
||||
Profiler::ReleaseReference();
|
||||
ProfilerDrillerBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnError
|
||||
// [2/8/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Update()
|
||||
{
|
||||
// \note We could add thread_id in addition to the System ID, but I can't foresee many cases where we would like to profile only a specific thread.
|
||||
if (m_numberOfValidFilters)
|
||||
{
|
||||
for (int iFilter = 0; iFilter < m_numberOfValidFilters; ++iFilter)
|
||||
{
|
||||
AZ::u32 systemFilter = *reinterpret_cast<AZ::u32*>(&m_systemFilters[iFilter].value);
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&ProfilerDriller::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2), systemFilter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&ProfilerDriller::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2), 0);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReadProfilerRegisters
|
||||
// [2/11/2013]
|
||||
//=========================================================================
|
||||
bool ProfilerDriller::ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id)
|
||||
{
|
||||
(void)id;
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("UpdateRegister", 0x6c00b890));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), ®);
|
||||
// Send only the data which is changing
|
||||
switch (reg.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Time", 0x6f949845), reg.m_timeData.m_time);
|
||||
m_output->Write(AZ_CRC("ChildrenTime", 0x46162d3f), reg.m_timeData.m_childrenTime);
|
||||
m_output->Write(AZ_CRC("Calls", 0xdaa35c8f), reg.m_timeData.m_calls);
|
||||
m_output->Write(AZ_CRC("ChildrenCalls", 0x6a5a4618), reg.m_timeData.m_childrenCalls);
|
||||
m_output->Write(AZ_CRC("ParentId", 0x856a684c), reg.m_timeData.m_lastParent);
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Value1", 0xa2756c5a), reg.m_userValues.m_value1);
|
||||
m_output->Write(AZ_CRC("Value2", 0x3b7c3de0), reg.m_userValues.m_value2);
|
||||
m_output->Write(AZ_CRC("Value3", 0x4c7b0d76), reg.m_userValues.m_value3);
|
||||
m_output->Write(AZ_CRC("Value4", 0xd21f98d5), reg.m_userValues.m_value4);
|
||||
m_output->Write(AZ_CRC("Value5", 0xa518a843), reg.m_userValues.m_value5);
|
||||
} break;
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("UpdateRegister", 0x6c00b890));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnThreadEnter
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnThreadEnter(const AZStd::thread_id& id, const AZStd::thread_desc* desc)
|
||||
{
|
||||
m_threads.push_back();
|
||||
ThreadInfo& info = m_threads.back();
|
||||
info.m_id = (size_t)id.m_id;
|
||||
if (desc)
|
||||
{
|
||||
info.m_name = desc->m_name;
|
||||
info.m_cpuId = desc->m_cpuId;
|
||||
info.m_priority = desc->m_priority;
|
||||
info.m_stackSize = desc->m_stackSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.m_name = nullptr;
|
||||
info.m_cpuId = -1;
|
||||
info.m_priority = -100000;
|
||||
info.m_stackSize = 0;
|
||||
}
|
||||
|
||||
if (m_output)
|
||||
{
|
||||
OutputThreadEnter(info);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnThreadExit
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnThreadExit(const AZStd::thread_id& id)
|
||||
{
|
||||
ThreadArrayType::iterator it = m_threads.begin();
|
||||
while (it != m_threads.end())
|
||||
{
|
||||
if (it->m_id == (size_t)id.m_id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != m_threads.end())
|
||||
{
|
||||
if (m_output)
|
||||
{
|
||||
OutputThreadExit(*it);
|
||||
}
|
||||
|
||||
m_threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OutputThreadEnter
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OutputThreadEnter(const ThreadInfo& threadInfo)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("ThreadEnter", 0x60e4acfb));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), threadInfo.m_id);
|
||||
if (threadInfo.m_name)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), threadInfo.m_name);
|
||||
}
|
||||
m_output->Write(AZ_CRC("CpuId", 0xdf558508), threadInfo.m_cpuId);
|
||||
m_output->Write(AZ_CRC("Priority", 0x62a6dc27), threadInfo.m_priority);
|
||||
m_output->Write(AZ_CRC("StackSize", 0x9cfaf35b), threadInfo.m_stackSize);
|
||||
m_output->EndTag(AZ_CRC("ThreadEnter", 0x60e4acfb));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OutputThreadExit
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OutputThreadExit(const ThreadInfo& threadInfo)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("OnThreadExit", 0x16042db9));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), threadInfo.m_id);
|
||||
m_output->EndTag(AZ_CRC("OnThreadExit", 0x16042db9));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnRegisterSystem
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnRegisterSystem(AZ::u32 id, const char* name)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("RegisterSystem", 0x957739ef));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), id);
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), name);
|
||||
m_output->EndTag(AZ_CRC("RegisterSystem", 0x957739ef));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnUnregisterSystem
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnUnregisterSystem(AZ::u32 id)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("UnregisterSystem", 0xa20538e4));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), id);
|
||||
m_output->EndTag(AZ_CRC("UnregisterSystem", 0xa20538e4));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnNewRegister
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("NewRegister", 0xf0f2f287));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), ®);
|
||||
m_output->Write(AZ_CRC("ThreadId", 0xd0fd9043), threadId.m_id);
|
||||
if (reg.m_name)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), reg.m_name);
|
||||
}
|
||||
if (reg.m_function)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Function", 0xcaae163d), reg.m_function);
|
||||
}
|
||||
m_output->Write(AZ_CRC("Line", 0xd114b4f6), reg.m_line);
|
||||
m_output->Write(AZ_CRC("SystemId", 0x0dfecf6f), reg.m_systemId);
|
||||
m_output->Write(AZ_CRC("Type", 0x8cde5729), reg.m_type);
|
||||
|
||||
switch (reg.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Time", 0x6f949845), reg.m_timeData.m_time);
|
||||
m_output->Write(AZ_CRC("ChildrenTime", 0x46162d3f), reg.m_timeData.m_childrenTime);
|
||||
m_output->Write(AZ_CRC("Calls", 0xdaa35c8f), reg.m_timeData.m_calls);
|
||||
m_output->Write(AZ_CRC("ChildrenCalls", 0x6a5a4618), reg.m_timeData.m_childrenCalls);
|
||||
m_output->Write(AZ_CRC("ParentId", 0x856a684c), reg.m_timeData.m_lastParent);
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Value1", 0xa2756c5a), reg.m_userValues.m_value1);
|
||||
m_output->Write(AZ_CRC("Value2", 0x3b7c3de0), reg.m_userValues.m_value2);
|
||||
m_output->Write(AZ_CRC("Value3", 0x4c7b0d76), reg.m_userValues.m_value3);
|
||||
m_output->Write(AZ_CRC("Value4", 0xd21f98d5), reg.m_userValues.m_value4);
|
||||
m_output->Write(AZ_CRC("Value5", 0xa518a843), reg.m_userValues.m_value5);
|
||||
} break;
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("NewRegister", 0xf0f2f287));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@@ -1,102 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_PROFILER_DRILLER_H
|
||||
#define AZCORE_PROFILER_DRILLER_H 1
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Debug/ProfilerDrillerBus.h>
|
||||
#include <AzCore/std/parallel/threadbus.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
struct thread_desc;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
struct ProfilerSystemData;
|
||||
class ProfilerRegister;
|
||||
|
||||
/**
|
||||
* ProfilerDriller or we can just make a Profiler driller and read the registers ourself.
|
||||
*/
|
||||
class ProfilerDriller
|
||||
: public Driller
|
||||
, public ProfilerDrillerBus::Handler
|
||||
, public AZStd::ThreadDrillerEventBus::Handler
|
||||
{
|
||||
struct ThreadInfo
|
||||
{
|
||||
AZ::u64 m_id;
|
||||
AZ::u32 m_stackSize;
|
||||
AZ::s32 m_priority;
|
||||
AZ::s32 m_cpuId;
|
||||
const char* m_name;
|
||||
};
|
||||
typedef vector<ThreadInfo>::type ThreadArrayType;
|
||||
|
||||
public:
|
||||
|
||||
AZ_CLASS_ALLOCATOR(ProfilerDriller, OSAllocator, 0)
|
||||
|
||||
ProfilerDriller();
|
||||
virtual ~ProfilerDriller();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller
|
||||
virtual const char* GroupName() const { return "SystemDrillers"; }
|
||||
virtual const char* GetName() const { return "ProfilerDriller"; }
|
||||
virtual const char* GetDescription() const { return "Collects data from all available profile registers."; }
|
||||
virtual int GetNumParams() const { return m_numberOfSystemFilters; }
|
||||
virtual const Param* GetParam(int index) const { AZ_Assert(index >= 0 && index < m_numberOfSystemFilters, "Invalid index"); return &m_systemFilters[index]; }
|
||||
virtual void Start(const Param* params = NULL, int numParams = 0);
|
||||
virtual void Stop();
|
||||
virtual void Update();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Thread driller event bus
|
||||
/// Called when we enter a thread, optional thread_desc is provided when the use provides one.
|
||||
virtual void OnThreadEnter(const AZStd::thread_id& id, const AZStd::thread_desc* desc);
|
||||
/// Called when we exit a thread.
|
||||
virtual void OnThreadExit(const AZStd::thread_id& id);
|
||||
|
||||
/// Output thread enter to stream.
|
||||
void OutputThreadEnter(const ThreadInfo& threadInfo);
|
||||
/// Output thread exit to stream.
|
||||
void OutputThreadExit(const ThreadInfo& threadInfo);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Profiler Driller bus
|
||||
virtual void OnRegisterSystem(AZ::u32 id, const char* name);
|
||||
|
||||
virtual void OnUnregisterSystem(AZ::u32 id);
|
||||
|
||||
virtual void OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Read profile registers callback.
|
||||
bool ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id);
|
||||
|
||||
|
||||
|
||||
static const int m_numberOfSystemFilters = 16;
|
||||
int m_numberOfValidFilters = 0 ; ///< Number of valid filter set when the driller was created.
|
||||
Param m_systemFilters[m_numberOfSystemFilters]; ///< If != 0, it's a ID of specific System we would like to drill.
|
||||
ThreadArrayType m_threads;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_PROFILER_DRILLER_H
|
||||
#pragma once
|
||||
@@ -1,45 +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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_PROFILER_DRILLER_BUS_H
|
||||
#define AZCORE_PROFILER_DRILLER_BUS_H
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class ProfilerRegister;
|
||||
|
||||
/**
|
||||
* ProfilerDrillerInterface driller profiler event interface, that records events from the profiler system.
|
||||
*/
|
||||
class ProfilerDrillerInterface
|
||||
: public DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~ProfilerDrillerInterface() {}
|
||||
|
||||
virtual void OnRegisterSystem(AZ::u32 id, const char* name) = 0;
|
||||
|
||||
virtual void OnUnregisterSystem(AZ::u32 id) = 0;
|
||||
|
||||
virtual void OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<ProfilerDrillerInterface> ProfilerDrillerBus;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_PROFILER_DRILLER_BUS_H
|
||||
#pragma once
|
||||
@@ -426,7 +426,6 @@ namespace AZ
|
||||
|
||||
void FileIOStream::Seek(OffsetType bytes, SeekMode mode)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AzCore, "FileIO Seek: %s", m_filename.c_str());
|
||||
AZ_Assert(FileIOBase::GetInstance(), "FileIO is not initialized.");
|
||||
AZ_Assert(IsOpen(), "Cannot seek on a FileIOStream that is not open.");
|
||||
|
||||
@@ -454,7 +453,6 @@ namespace AZ
|
||||
|
||||
SizeType FileIOStream::Read(SizeType bytes, void* oBuffer)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(AzCore, "FileIO Read: %s", m_filename.c_str());
|
||||
AZ_Assert(FileIOBase::GetInstance(), "FileIO is not initialized.");
|
||||
AZ_Assert(IsOpen(), "Cannot read from a FileIOStream that is not open.");
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace UnitTest
|
||||
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetEngineRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
|
||||
};
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Memory/MemoryDriller.h>
|
||||
|
||||
@@ -93,20 +93,18 @@ set(FILES
|
||||
Debug/AssetTracking.h
|
||||
Debug/AssetTrackingTypesImpl.h
|
||||
Debug/AssetTrackingTypes.h
|
||||
Debug/Budget.h
|
||||
Debug/Budget.cpp
|
||||
Debug/BudgetTracker.h
|
||||
Debug/BudgetTracker.cpp
|
||||
Debug/LocalFileEventLogger.h
|
||||
Debug/LocalFileEventLogger.cpp
|
||||
Debug/FrameProfiler.h
|
||||
Debug/FrameProfilerBus.h
|
||||
Debug/FrameProfilerComponent.cpp
|
||||
Debug/FrameProfilerComponent.h
|
||||
Debug/IEventLogger.h
|
||||
Debug/MemoryProfiler.h
|
||||
Debug/Profiler.cpp
|
||||
Debug/Profiler.inl
|
||||
Debug/Profiler.h
|
||||
Debug/ProfilerBus.h
|
||||
Debug/ProfilerDriller.cpp
|
||||
Debug/ProfilerDriller.h
|
||||
Debug/ProfilerDrillerBus.h
|
||||
Debug/StackTracer.h
|
||||
Debug/EventTrace.h
|
||||
Debug/EventTrace.cpp
|
||||
@@ -572,8 +570,6 @@ set(FILES
|
||||
Statistics/StatisticalProfilerProxySystemComponent.cpp
|
||||
Statistics/StatisticalProfilerProxySystemComponent.h
|
||||
Statistics/StatisticsManager.h
|
||||
Statistics/TimeDataStatisticsManager.cpp
|
||||
Statistics/TimeDataStatisticsManager.h
|
||||
StringFunc/StringFunc.cpp
|
||||
StringFunc/StringFunc.h
|
||||
UserSettings/UserSettings.cpp
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace UnitTest
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
////
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#include <AzCore/Debug/FrameProfilerBus.h>
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
|
||||
@@ -1,698 +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 <time.h>
|
||||
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/Driller/DrillerRootHandler.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
//#define AZ_CORE_DRILLER_COMPARE_TEST
|
||||
#if defined(AZ_CORE_DRILLER_COMPARE_TEST)
|
||||
# include <AzCore/IO/GenericStreams.h>
|
||||
# include <AzCore/Serialization/ObjectStream.h>
|
||||
# include <AzCore/Serialization/SerializeContext.h>
|
||||
#endif
|
||||
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace AZ::Debug;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
/**
|
||||
* MyDriller event bus...
|
||||
*/
|
||||
class MyDrillerInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerInterface() {}
|
||||
// define one event X
|
||||
virtual void OnEventX(int data) = 0;
|
||||
// define a string event
|
||||
virtual void OnStringEvent() = 0;
|
||||
};
|
||||
|
||||
class MyDrillerCommandInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerCommandInterface() {}
|
||||
|
||||
virtual class MyDrilledObject* RequestDrilledObject() = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<MyDrillerInterface> MyDrillerBus;
|
||||
typedef AZ::EBus<MyDrillerCommandInterface> MyDrillerCommandBus;
|
||||
|
||||
class MyDrilledObject
|
||||
: public MyDrillerCommandBus::Handler
|
||||
{
|
||||
int i;
|
||||
public:
|
||||
MyDrilledObject()
|
||||
: i(0)
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
~MyDrilledObject() override
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MyDrillerCommandBus
|
||||
MyDrilledObject* RequestDrilledObject() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnEventX()
|
||||
{
|
||||
EBUS_EVENT(MyDrillerBus, OnEventX, i);
|
||||
++i;
|
||||
}
|
||||
|
||||
void OnStringEvent()
|
||||
{
|
||||
EBUS_DBG_EVENT(MyDrillerBus, OnStringEvent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* My driller implements the driller interface and an handles the MyDrillerBus events...
|
||||
*/
|
||||
class MyDriller
|
||||
: public Driller
|
||||
, public MyDrillerBus::Handler
|
||||
{
|
||||
bool m_isDetailedCapture;
|
||||
class MyDrilledObject* drilledObject;
|
||||
typedef vector<Param>::type ParamArrayType;
|
||||
ParamArrayType m_params;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MyDriller, OSAllocator, 0);
|
||||
|
||||
const char* GroupName() const override { return "TestDrillers"; }
|
||||
const char* GetName() const override { return "MyTestDriller"; }
|
||||
const char* GetDescription() const override { return "MyTestDriller description...."; }
|
||||
int GetNumParams() const override { return static_cast<int>(m_params.size()); }
|
||||
const Param* GetParam(int index) const override { return &m_params[index]; }
|
||||
|
||||
MyDriller()
|
||||
: m_isDetailedCapture(false)
|
||||
, drilledObject(NULL)
|
||||
{
|
||||
Param isDetailed;
|
||||
isDetailed.desc = "IsDetailedDrill";
|
||||
isDetailed.name = AZ_CRC("IsDetailedDrill", 0x2155cef2);
|
||||
isDetailed.type = Param::PT_BOOL;
|
||||
isDetailed.value = 0;
|
||||
m_params.push_back(isDetailed);
|
||||
}
|
||||
|
||||
void Start(const Param* params = NULL, int numParams = 0) override
|
||||
{
|
||||
m_isDetailedCapture = m_params[0].value != 0;
|
||||
if (params)
|
||||
{
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
if (params[i].name == m_params[0].name)
|
||||
{
|
||||
m_isDetailedCapture = params[i].value != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT_RESULT(drilledObject, MyDrillerCommandBus, RequestDrilledObject);
|
||||
AZ_TEST_ASSERT(drilledObject != NULL); /// Make sure we have our object by the time we started the driller
|
||||
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStart", 0x8b372fca), m_isDetailedCapture);
|
||||
// write drilled object initial state
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
|
||||
BusConnect();
|
||||
}
|
||||
void Stop() override
|
||||
{
|
||||
drilledObject = NULL;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStop", 0xf6701caa), m_isDetailedCapture);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
void OnEventX(int data) override
|
||||
{
|
||||
void* ptr = AZ_INVALID_POINTER;
|
||||
float f = 3.2f;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("EventX", 0xc4558ec2), data);
|
||||
m_output->Write(AZ_CRC("Pointer", 0x320468a8), ptr);
|
||||
m_output->Write(AZ_CRC("Float", 0xc9a55e95), f);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
|
||||
void OnStringEvent() override
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->BeginTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->Write(AZ_CRC("StringOne", 0x56efb231), "This is copied string");
|
||||
m_output->Write(AZ_CRC("StringTwo", 0x3d49bea6), "This is referenced string", false); // don't copy the string if we use string pool, this will be faster as we don't delete the string
|
||||
m_output->EndTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FileStreamDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
int m_lastData;
|
||||
|
||||
MyDrillerHandler()
|
||||
: m_lastData(-1) {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
(void)tagName;
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("EventX", 0xc4558ec2))
|
||||
{
|
||||
int data;
|
||||
dataNode.Read(data);
|
||||
AZ_TEST_ASSERT(data > m_lastData);
|
||||
m_lastData = data;
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Pointer", 0x320468a8))
|
||||
{
|
||||
AZ::u64 pointer = 0; //< read pointers in u64 to cover all platforms
|
||||
dataNode.Read(pointer);
|
||||
AZ_TEST_ASSERT(pointer == 0x0badf00dul);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Float", 0xc9a55e95))
|
||||
{
|
||||
float f;
|
||||
dataNode.Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
AZ_TEST_ASSERT(driller != NULL);
|
||||
AZ_TEST_ASSERT(strcmp(driller->GetName(), "MyTestDriller") == 0);
|
||||
AZ_TEST_ASSERT(driller->GetNumParams() == 1);
|
||||
|
||||
// read the default params and make a copy...
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
// open a driller output file stream
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "drilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object
|
||||
MyDrilledObject myDrilledObject;
|
||||
clock_t st = clock();
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
DrillerSession* drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
// trigger event X that we want to drill...
|
||||
myDrilledObject.OnEventX();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
AZ_Printf("Driller", "Compression time %.09f seconds\n", (double)(clock() - st) / CLOCKS_PER_SEC);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// try to load the drill data
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
DrillerDOMParser dp;
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
dp.ProcessStream(drillerInputStream);
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
drillerInputStream.Close();
|
||||
|
||||
u32 startDataId = AZ_CRC("StartData", 0xecf3f53f);
|
||||
u32 frameId = AZ_CRC("Frame", 0xb5f83ccd);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// read all data
|
||||
const DrillerDOMParser::Node* root = dp.GetRootNode();
|
||||
int lastFrame = -1;
|
||||
int lastData = -1;
|
||||
for (DrillerDOMParser::Node::NodeListType::const_iterator iter = root->m_tags.begin(); iter != root->m_tags.end(); ++iter)
|
||||
{
|
||||
const DrillerDOMParser::Node* node = &*iter;
|
||||
u32 name = node->m_name;
|
||||
AZ_TEST_ASSERT(name == startDataId || name == frameId);
|
||||
if (name == startDataId)
|
||||
{
|
||||
unsigned int currentPlatform;
|
||||
node->GetDataRequired(AZ_CRC("Platform", 0x3952d0cb))->Read(currentPlatform);
|
||||
AZ_TEST_ASSERT(currentPlatform == static_cast<int>(AZ::g_currentPlatform));
|
||||
const DrillerDOMParser::Node* drillerNode = node->GetTag(AZ_CRC("Driller", 0xa6e1fb73));
|
||||
AZ_TEST_ASSERT(drillerNode != NULL);
|
||||
AZ::u32 drillerName;
|
||||
drillerNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(drillerName);
|
||||
AZ_TEST_ASSERT(drillerName == m_driller->GetId());
|
||||
const DrillerDOMParser::Node* paramNode = drillerNode->GetTag(AZ_CRC("Param", 0xa4fa7c89));
|
||||
AZ_TEST_ASSERT(paramNode != NULL);
|
||||
u32 paramName;
|
||||
char paramDesc[128];
|
||||
int paramType;
|
||||
int paramValue;
|
||||
paramNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(paramName);
|
||||
AZ_TEST_ASSERT(paramName == param.name);
|
||||
paramNode->GetDataRequired(AZ_CRC("Description", 0x6de44026))->Read(paramDesc, AZ_ARRAY_SIZE(paramDesc));
|
||||
AZ_TEST_ASSERT(strcmp(paramDesc, param.desc) == 0);
|
||||
paramNode->GetDataRequired(AZ_CRC("Type", 0x8cde5729))->Read(paramType);
|
||||
AZ_TEST_ASSERT(paramType == param.type);
|
||||
paramNode->GetDataRequired(AZ_CRC("Value", 0x1d775834))->Read(paramValue);
|
||||
AZ_TEST_ASSERT(paramValue == param.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
int curFrame;
|
||||
node->GetDataRequired(AZ_CRC("FrameNum", 0x85a1a919))->Read(curFrame);
|
||||
AZ_TEST_ASSERT(curFrame > lastFrame); // check order
|
||||
lastFrame = curFrame;
|
||||
const DrillerDOMParser::Node* myDrillerNode = node->GetTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
AZ_TEST_ASSERT(myDrillerNode != NULL);
|
||||
const DrillerDOMParser::Data* dataEntry;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("EventX", 0xc4558ec2));
|
||||
if (dataEntry)
|
||||
{
|
||||
int data;
|
||||
dataEntry->Read(data);
|
||||
AZ_TEST_ASSERT(data > lastData);
|
||||
lastData = data;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Pointer", 0x320468a8));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
unsigned int ptr;
|
||||
dataEntry->Read(ptr);
|
||||
AZ_TEST_ASSERT(static_cast<size_t>(ptr) == reinterpret_cast<size_t>(AZ_INVALID_POINTER));
|
||||
float f;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Float", 0xc9a55e95));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
dataEntry->Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("OnStart", 0x8b372fca));
|
||||
if (dataEntry)
|
||||
{
|
||||
dataEntry->Read(isDetailedCapture);
|
||||
}
|
||||
else
|
||||
{
|
||||
myDrillerNode->GetDataRequired(AZ_CRC("OnStop", 0xf6701caa))->Read(isDetailedCapture);
|
||||
}
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read that with Tag Handlers
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
// Verify that Default templates forked fine...
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_platform == static_cast<uint32_t>(AZ::g_currentPlatform));
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_drillers.size() == 1);
|
||||
{
|
||||
const DrillerManager::DrillerInfo& dinfo = rootHandler.m_drillerSessionInfo.m_drillers.front();
|
||||
AZ_TEST_ASSERT(dinfo.id == AZ_CRC("MyTestDriller", 0x5cc4edf5));
|
||||
AZ_TEST_ASSERT(dinfo.params.size() == 1);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
AZ_TEST_ASSERT(dinfo.params[0].name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(dinfo.params[0].desc == NULL); // ignored for now
|
||||
AZ_TEST_ASSERT(dinfo.params[0].type == Driller::Param::PT_BOOL);
|
||||
AZ_TEST_ASSERT(dinfo.params[0].value == 1);
|
||||
}
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FileStreamDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class StringPoolDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
|
||||
MyDrillerHandler() {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
if (tagName == AZ_CRC("StringEvent", 0xd1e005df))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringOne", 0x56efb231))
|
||||
{
|
||||
// read string as a copy
|
||||
char stringCopy[256];
|
||||
dataNode.Read(stringCopy, AZ_ARRAY_SIZE(stringCopy));
|
||||
AZ_TEST_ASSERT(strcmp(stringCopy, "This is copied string") == 0);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringTwo", 0x3d49bea6))
|
||||
{
|
||||
// read string as reference if possible, otherwise read it as a copy
|
||||
const char* stringRef = dataNode.ReadPooledString();
|
||||
AZ_TEST_ASSERT(strcmp(stringRef, "This is referenced string") == 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
param.value = 1;
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
MyDrilledObject myDrilledObject;
|
||||
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "stringpooldrilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
DrillerDefaultStringPool stringPool;
|
||||
DrillerSession* drillerSession;
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
stringPool.Reset();
|
||||
drillerOutputStream.SetStringPool(&stringPool); // set the string pool on save
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
stringPool.Reset();
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(StringPoolDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DrillFileStreamCheck
|
||||
{
|
||||
public:
|
||||
void run()
|
||||
{
|
||||
// open and read drilled file
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller application test
|
||||
*/
|
||||
TEST(DrillerApplication, Test)
|
||||
{
|
||||
ComponentApplication app;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Create application environment code driven
|
||||
ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
|
||||
appDesc.m_enableDrilling = true;
|
||||
Entity* systemEntity = app.Create(appDesc);
|
||||
|
||||
systemEntity->CreateComponent<MemoryComponent>();
|
||||
systemEntity->CreateComponent<StreamerComponent>(); // note that this component is what registers the streamer driller
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate();
|
||||
|
||||
{
|
||||
// open a driller output file stream
|
||||
char testFileName[AZ_MAX_PATH_LEN];
|
||||
MakePathFromTestFolder(testFileName, AZ_MAX_PATH_LEN, "drillapptest.dat");
|
||||
DrillerOutputFileStream fs;
|
||||
fs.Open(testFileName, IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType drillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = AZ_CRC("TraceMessagesDriller", 0xa61d1b00);
|
||||
drillersToDrill.push_back(di);
|
||||
di.id = AZ_CRC("MemoryDriller", 0x1b31269d);
|
||||
drillersToDrill.push_back(di);
|
||||
|
||||
ASSERT_NE(nullptr, app.GetDrillerManager());
|
||||
DrillerSession* drillerSession = app.GetDrillerManager()->Start(fs, drillersToDrill);
|
||||
ASSERT_NE(nullptr, drillerSession);
|
||||
|
||||
const int numOfFrames = 10000;
|
||||
void* memory = NULL;
|
||||
for (int i = 0; i < numOfFrames; ++i)
|
||||
{
|
||||
memory = azmalloc(rand() % 2048 + 1);
|
||||
azfree(memory);
|
||||
app.Tick();
|
||||
}
|
||||
|
||||
app.GetDrillerManager()->Stop(drillerSession); // stop session manually
|
||||
fs.Close(); // close the file with driller info
|
||||
}
|
||||
|
||||
app.Destroy();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
}
|
||||
@@ -1242,7 +1242,6 @@ namespace UnitTest
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,208 +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 <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
|
||||
#include <AzCore/Statistics/TimeDataStatisticsManager.h>
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/EntityUtils.h>
|
||||
#include <AzCore/Debug/FrameProfilerBus.h>
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace Debug;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
/**
|
||||
* Validate functionality of the convenience class TimeDataStatisticsManager.
|
||||
* It is a specialized version of RunningStatisticsManager that works with Timer type
|
||||
* of registers that can be captured with the FrameProfilerBus::OnFrameProfilerData()
|
||||
*/
|
||||
class TimeDataStatisticsManagerTest
|
||||
: public AllocatorsFixture
|
||||
, public FrameProfilerBus::Handler
|
||||
{
|
||||
static constexpr const char* PARENT_TIMER_STAT = "ParentStat";
|
||||
static constexpr const char* CHILD_TIMER_STAT0 = "ChildStat0";
|
||||
static constexpr const char* CHILD_TIMER_STAT1 = "ChildStat1";
|
||||
|
||||
public:
|
||||
TimeDataStatisticsManagerTest()
|
||||
: AllocatorsFixture()
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
m_statsManager = AZStd::make_unique<Statistics::TimeDataStatisticsManager>();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_statsManager = nullptr;
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FrameProfilerBus
|
||||
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data)
|
||||
{
|
||||
for (size_t iThread = 0; iThread < data.size(); ++iThread)
|
||||
{
|
||||
const FrameProfiler::ThreadData& td = data[iThread];
|
||||
FrameProfiler::ThreadData::RegistersMap::const_iterator regIt = td.m_registers.begin();
|
||||
for (; regIt != td.m_registers.end(); ++regIt)
|
||||
{
|
||||
const FrameProfiler::RegisterData& rd = regIt->second;
|
||||
u32 unitTestCrc = AZ_CRC("UnitTest", 0x8089cea8);
|
||||
if (unitTestCrc != rd.m_systemId)
|
||||
{
|
||||
continue; //Not for us.
|
||||
}
|
||||
ASSERT_EQ(ProfilerRegister::PRT_TIME, rd.m_type);
|
||||
const FrameProfiler::FrameData& fd = rd.m_frames.back();
|
||||
m_statsManager->PushTimeDataSample(rd.m_name, fd.m_timeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ChildFunction0(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, CHILD_TIMER_STAT0);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 5;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
result += i % 3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ChildFunction1(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, CHILD_TIMER_STAT1);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 5;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
result += i % 3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ParentFunction(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, PARENT_TIMER_STAT);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 0;
|
||||
result += ChildFunction0(numIterations, sleepTimeMilliseconds);
|
||||
result += ChildFunction1(numIterations, sleepTimeMilliseconds);
|
||||
return result;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Debug::FrameProfilerBus::Handler::BusConnect();
|
||||
|
||||
ComponentApplication app;
|
||||
ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
|
||||
ComponentApplication::StartupParameters startupParams;
|
||||
startupParams.m_allocator = &AllocatorInstance<SystemAllocator>::Get();
|
||||
Entity* systemEntity = app.Create(desc, startupParams);
|
||||
systemEntity->CreateComponent<FrameProfilerComponent>();
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate(); // start frame component
|
||||
|
||||
const int sleepTimeAllFuncsMillis = 1;
|
||||
const int numIterations = 10;
|
||||
for (int iterationCounter = 0; iterationCounter < numIterations; ++iterationCounter)
|
||||
{
|
||||
ParentFunction(numIterations, sleepTimeAllFuncsMillis);
|
||||
//Collect all samples.
|
||||
app.Tick();
|
||||
}
|
||||
|
||||
//Verify we have three running stats.
|
||||
{
|
||||
AZStd::vector<Statistics::NamedRunningStatistic*> allStats;
|
||||
m_statsManager->GetAllStatistics(allStats);
|
||||
EXPECT_EQ(allStats.size(), 3);
|
||||
}
|
||||
|
||||
AZStd::string parentStatName(PARENT_TIMER_STAT);
|
||||
AZStd::string child0StatName(CHILD_TIMER_STAT0);
|
||||
AZStd::string child1StatName(CHILD_TIMER_STAT1);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
|
||||
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numIterations);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numIterations);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), numIterations);
|
||||
|
||||
const double minimumExpectDurationOfChildFunctionMicros = 1;
|
||||
const double minimumExpectDurationOfParentFunctionMicros = 1;
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMinimum(), minimumExpectDurationOfParentFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetAverage(), minimumExpectDurationOfParentFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMaximum(), minimumExpectDurationOfParentFunctionMicros);
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
|
||||
//Let's validate TimeDataStatisticsManager::RemoveStatistics()
|
||||
m_statsManager->RemoveStatistic(child1StatName);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName), nullptr);
|
||||
|
||||
//Let's store the sample count for both parentStatName and child0StatName.
|
||||
const AZ::u64 numSamplesParent = m_statsManager->GetStatistic(parentStatName)->GetNumSamples();
|
||||
const AZ::u64 numSamplesChild0 = m_statsManager->GetStatistic(child0StatName)->GetNumSamples();
|
||||
|
||||
//Let's call child1 function again and call app.Tick(). child1StatName should be readded to m_statsManager.
|
||||
ChildFunction1(numIterations, sleepTimeAllFuncsMillis);
|
||||
app.Tick();
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numSamplesParent);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numSamplesChild0);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), 1);
|
||||
|
||||
Debug::FrameProfilerBus::Handler::BusDisconnect();
|
||||
app.Destroy();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<Statistics::TimeDataStatisticsManager> m_statsManager;
|
||||
};//class TimeDataStatisticsManagerTest
|
||||
|
||||
// TODO:BUDGETS disabled until profiler budgets system comes online
|
||||
// TEST_F(TimeDataStatisticsManagerTest, Test)
|
||||
// {
|
||||
// run();
|
||||
// }
|
||||
//End of all Tests of TimeDataStatisticsManagerTest
|
||||
|
||||
}//namespace UnitTest
|
||||
@@ -29,7 +29,6 @@ set(FILES
|
||||
Console/ConsoleTests.cpp
|
||||
Debug.cpp
|
||||
DLL.cpp
|
||||
Driller.cpp
|
||||
EBus.cpp
|
||||
EntityIdTests.cpp
|
||||
EntityTests.cpp
|
||||
@@ -66,7 +65,6 @@ set(FILES
|
||||
SystemFile.cpp
|
||||
TaskTests.cpp
|
||||
TickBusTest.cpp
|
||||
TimeDataStatistics.cpp
|
||||
UUIDTests.cpp
|
||||
XML.cpp
|
||||
Debug/AssetTracking.cpp
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/Serialization/DataPatch.h>
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
#include <AzCore/NativeUI/NativeUISystemComponent.h>
|
||||
#include <AzCore/Module/ModuleManagerBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
@@ -60,7 +59,6 @@
|
||||
#include <AzFramework/StreamingInstall/StreamingInstall.h>
|
||||
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzFramework/Metrics/MetricsPlainTextNameRegistration.h>
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
@@ -296,7 +294,6 @@ namespace AzFramework
|
||||
azrtti_typeid<AZ::JobManagerComponent>(),
|
||||
azrtti_typeid<AZ::AssetManagerComponent>(),
|
||||
azrtti_typeid<AZ::UserSettingsComponent>(),
|
||||
azrtti_typeid<AZ::Debug::FrameProfilerComponent>(),
|
||||
azrtti_typeid<AZ::SliceComponent>(),
|
||||
azrtti_typeid<AZ::SliceSystemComponent>(),
|
||||
|
||||
@@ -312,7 +309,6 @@ namespace AzFramework
|
||||
#endif
|
||||
azrtti_typeid<AzFramework::AssetSystem::AssetSystemComponent>(),
|
||||
azrtti_typeid<AzFramework::InputSystemComponent>(),
|
||||
azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>(),
|
||||
|
||||
#if !defined(AZCORE_EXCLUDE_LUA)
|
||||
azrtti_typeid<AZ::ScriptSystemComponent>(),
|
||||
@@ -374,7 +370,6 @@ namespace AzFramework
|
||||
azrtti_typeid<AzFramework::RenderGeometry::GameIntersectorComponent>(),
|
||||
azrtti_typeid<AzFramework::AssetSystem::AssetSystemComponent>(),
|
||||
azrtti_typeid<AzFramework::InputSystemComponent>(),
|
||||
azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>(),
|
||||
azrtti_typeid<AzFramework::StreamingInstall::StreamingInstallSystemComponent>(),
|
||||
azrtti_typeid<AzFramework::SpawnableSystemComponent>(),
|
||||
AZ::Uuid("{624a7be2-3c7e-4119-aee2-1db2bdb6cc89}"), // ScriptDebugAgent
|
||||
|
||||
@@ -191,3 +191,5 @@ namespace AzFramework
|
||||
};
|
||||
} // namespace AzFramework
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzFramework/Components/AzFrameworkConfigurationSystemComponent.h>
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzFramework/Entity/GameEntityContextComponent.h>
|
||||
#include <AzFramework/FileTag/FileTagComponent.h>
|
||||
#include <AzFramework/Input/System/InputSystemComponent.h>
|
||||
@@ -27,6 +26,8 @@
|
||||
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
|
||||
#include <AzFramework/Visibility/OctreeSystemComponent.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzFramework);
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
AzFrameworkModule::AzFrameworkModule()
|
||||
@@ -46,7 +47,6 @@ namespace AzFramework
|
||||
AzFramework::CreateScriptDebugAgentFactory(),
|
||||
AzFramework::AssetSystem::AssetSystemComponent::CreateDescriptor(),
|
||||
AzFramework::InputSystemComponent::CreateDescriptor(),
|
||||
AzFramework::DrillerNetworkAgentComponent::CreateDescriptor(),
|
||||
|
||||
#if !defined(AZCORE_EXCLUDE_LUA)
|
||||
AzFramework::ScriptComponent::CreateDescriptor(),
|
||||
|
||||
@@ -1,197 +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 <AzFramework/Driller/DrillToFileComponent.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void DrillToFileComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DrillToFileComponent, AZ::Component>()
|
||||
;
|
||||
|
||||
if (serialize->FindClassData(DrillerInfo::RTTI_Type()) == nullptr)
|
||||
{
|
||||
serialize->Class<DrillerInfo>()
|
||||
->Field("Id", &DrillerInfo::m_id)
|
||||
->Field("GroupName", &DrillerInfo::m_groupName)
|
||||
->Field("Name", &DrillerInfo::m_name)
|
||||
->Field("Description", &DrillerInfo::m_description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::Activate()
|
||||
{
|
||||
m_drillerSession = nullptr;
|
||||
DrillerConsoleCommandBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void DrillToFileComponent::Deactivate()
|
||||
{
|
||||
DrillerConsoleCommandBus::Handler::BusDisconnect();
|
||||
StopDrillerSession(reinterpret_cast<AZ::u64>(this));
|
||||
}
|
||||
|
||||
void DrillToFileComponent::WriteBinary(const void* data, unsigned int dataSize)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
m_frameBuffer.insert(m_frameBuffer.end(), reinterpret_cast<const AZ::u8*>(data), reinterpret_cast<const AZ::u8*>(data) + dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::OnEndOfFrame()
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> lock(m_writerMutex);
|
||||
m_writeQueue.push_back();
|
||||
m_writeQueue.back().swap(m_frameBuffer);
|
||||
m_signal.notify_all();
|
||||
}
|
||||
|
||||
void DrillToFileComponent::EnumerateAvailableDrillers()
|
||||
{
|
||||
DrillerInfoListType availableDrillers;
|
||||
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
for (int i = 0; i < mgr->GetNumDrillers(); ++i)
|
||||
{
|
||||
AZ::Debug::Driller* driller = mgr->GetDriller(i);
|
||||
AZ_Assert(driller, "DrillerManager returned a NULL driller. This is not legal!");
|
||||
availableDrillers.push_back();
|
||||
availableDrillers.back().m_id = driller->GetId();
|
||||
availableDrillers.back().m_groupName = driller->GroupName();
|
||||
availableDrillers.back().m_name = driller->GetName();
|
||||
availableDrillers.back().m_description = driller->GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillersEnumerated, availableDrillers);
|
||||
}
|
||||
|
||||
void DrillToFileComponent::StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId)
|
||||
{
|
||||
if (!m_drillerSession)
|
||||
{
|
||||
AZ_Assert(m_writeQueue.empty(), "write queue is not empty!");
|
||||
|
||||
m_sessionId = sessionId;
|
||||
AZ::Debug::DrillerManager* mgr = nullptr;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
SetStringPool(&m_stringPool);;
|
||||
m_drillerSession = mgr->Start(*this, requestedDrillers);
|
||||
|
||||
AZStd::unique_lock<AZStd::mutex> signalLock(m_writerMutex);
|
||||
m_isWriterEnabled = true;
|
||||
AZStd::thread_desc td;
|
||||
td.m_name = "DrillToFileComponent Writer Thread";
|
||||
m_writerThread = AZStd::thread(AZStd::bind(&DrillToFileComponent::AsyncWritePump, this), &td);
|
||||
m_signal.wait(signalLock);
|
||||
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillerSessionStarted, sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::StopDrillerSession(AZ::u64 sessionId)
|
||||
{
|
||||
if (sessionId == m_sessionId)
|
||||
{
|
||||
if (m_drillerSession)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop(m_drillerSession);
|
||||
}
|
||||
m_drillerSession = nullptr;
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillerSessionStopped, reinterpret_cast<AZ::u64>(this));
|
||||
}
|
||||
|
||||
m_isWriterEnabled = false;
|
||||
if (m_writerThread.joinable())
|
||||
{
|
||||
m_writerMutex.lock();
|
||||
m_signal.notify_all();
|
||||
m_writerMutex.unlock();
|
||||
m_writerThread.join();
|
||||
}
|
||||
SetStringPool(nullptr);
|
||||
m_stringPool.Reset();
|
||||
m_frameBuffer.clear(); // there may be pending data but we don't want to write it because it's an incomplete frame.
|
||||
}
|
||||
}
|
||||
void DrillToFileComponent::AsyncWritePump()
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> signalLock(m_writerMutex);
|
||||
|
||||
AZStd::basic_string<char, AZStd::char_traits<char>, AZ::OSStdAllocator> drillerOutputPath;
|
||||
|
||||
// Try the log path first
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
if (fileIO)
|
||||
{
|
||||
const char* logLocation = fileIO->GetAlias("@log@");
|
||||
if (logLocation)
|
||||
{
|
||||
drillerOutputPath = logLocation;
|
||||
drillerOutputPath.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
// Try the executable path
|
||||
if (drillerOutputPath.empty())
|
||||
{
|
||||
EBUS_EVENT_RESULT(drillerOutputPath, AZ::ComponentApplicationBus, GetExecutableFolder);
|
||||
drillerOutputPath.append("/");
|
||||
}
|
||||
|
||||
drillerOutputPath.append("drillerdata.drl");
|
||||
AZ::IO::SystemFile output;
|
||||
output.Open(drillerOutputPath.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
AZ_Assert(output.IsOpen(), "Failed to open driller output file!");
|
||||
|
||||
m_signal.notify_all();
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (!m_writeQueue.empty())
|
||||
{
|
||||
AZStd::vector<AZ::u8, AZ::OSStdAllocator> outBuffer;
|
||||
outBuffer.swap(m_writeQueue.front());
|
||||
m_writeQueue.pop_front();
|
||||
signalLock.unlock();
|
||||
|
||||
output.Write(outBuffer.data(), outBuffer.size());
|
||||
output.Flush();
|
||||
|
||||
signalLock.lock();
|
||||
}
|
||||
if (!m_isWriterEnabled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_signal.wait(signalLock);
|
||||
}
|
||||
|
||||
output.Close();
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -1,74 +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 <AzFramework/Driller/DrillerConsoleAPI.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
|
||||
//#define ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
struct ClassDataReflection;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/**
|
||||
* Runs on the machine being drilled and is responsible for communications
|
||||
* with the DrillerNetworkConsole running on the tool side as well as
|
||||
* creating DrillerNetSessionStreams for each driller session being started.
|
||||
*/
|
||||
class DrillToFileComponent
|
||||
: public AZ::Component
|
||||
, public AZ::Debug::DrillerOutputStream
|
||||
, public DrillerConsoleCommandBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillToFileComponent, "{42BAA25D-7CEB-4A37-8BD4-4A1FE2253894}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerOutputStream
|
||||
void WriteBinary(const void* data, unsigned int dataSize) override;
|
||||
void OnEndOfFrame() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerConsoleCommandBus
|
||||
void EnumerateAvailableDrillers() override;
|
||||
void StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId) override;
|
||||
void StopDrillerSession(AZ::u64 sessionId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
void AsyncWritePump();
|
||||
|
||||
AZ::u64 m_sessionId;
|
||||
AZ::Debug::DrillerSession* m_drillerSession;
|
||||
AZ::Debug::DrillerDefaultStringPool m_stringPool;
|
||||
AZStd::vector<AZ::u8, AZ::OSStdAllocator> m_frameBuffer;
|
||||
AZStd::deque<AZStd::vector<AZ::u8, AZ::OSStdAllocator>, AZ::OSStdAllocator> m_writeQueue;
|
||||
AZStd::mutex m_writerMutex;
|
||||
AZStd::condition_variable m_signal;
|
||||
AZStd::thread m_writerThread;
|
||||
bool m_isWriterEnabled;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
@@ -1,79 +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 <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/*
|
||||
* Descriptors for drillers available on the target machine.
|
||||
*/
|
||||
struct DrillerInfo final
|
||||
{
|
||||
AZ_RTTI(DrillerInfo, "{197AC318-B65C-4B36-A109-BD25422BF7D0}");
|
||||
AZ::u32 m_id;
|
||||
AZStd::string m_groupName;
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_description;
|
||||
};
|
||||
|
||||
typedef AZStd::vector<DrillerInfo> DrillerInfoListType;
|
||||
typedef AZStd::vector<AZ::u32> DrillerListType;
|
||||
|
||||
/**
|
||||
* Driller clients interested in receiving notification events from the
|
||||
* console should implement this interface.
|
||||
*/
|
||||
class DrillerConsoleEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerConsoleEvents() {}
|
||||
|
||||
// A list of available drillers has been received from the target machine.
|
||||
virtual void OnDrillersEnumerated(const DrillerInfoListType& availableDrillers) = 0;
|
||||
virtual void OnDrillerSessionStarted(AZ::u64 sessionId) = 0;
|
||||
virtual void OnDrillerSessionStopped(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerConsoleEvents> DrillerConsoleEventBus;
|
||||
|
||||
/**
|
||||
* Commands can be sent to the driller through this interface.
|
||||
*/
|
||||
class DrillerConsoleCommands
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
|
||||
// there's only one driller console instance allowed
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerConsoleCommands() {}
|
||||
|
||||
// Request an enumeration of available drillers from the target machine
|
||||
virtual void EnumerateAvailableDrillers() = 0;
|
||||
// Start a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId) = 0;
|
||||
// Stop a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StopDrillerSession(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerConsoleCommands> DrillerConsoleCommandBus;
|
||||
} // namespace AzFramework
|
||||
@@ -1,740 +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 <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/Stream.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//---------------------------------------------------------------------
|
||||
// TEMP FOR DEBUGGING ONLY!!!
|
||||
//---------------------------------------------------------------------
|
||||
class DebugDrillerRemoteSession
|
||||
: public DrillerRemoteSession
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DebugDrillerRemoteSession, AZ::OSAllocator, 0);
|
||||
|
||||
DebugDrillerRemoteSession()
|
||||
{
|
||||
AZStd::string filename = AZStd::string::format("remotedrill_%llu", static_cast<AZ::u64>(reinterpret_cast<size_t>(static_cast<DrillerRemoteSession*>(this))));
|
||||
m_file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
}
|
||||
|
||||
~DebugDrillerRemoteSession()
|
||||
{
|
||||
m_file.Close();
|
||||
}
|
||||
|
||||
virtual void ProcessIncomingDrillerData(const char* streamIdentifier, const void* data, size_t dataSize)
|
||||
{
|
||||
(void)streamIdentifier;
|
||||
|
||||
m_file.Write(data, dataSize);
|
||||
}
|
||||
|
||||
virtual void OnDrillerConnectionLost()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile m_file;
|
||||
};
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* These are the different synchronization messages that are used.
|
||||
*/
|
||||
namespace NetworkDrillerSyncMsgId
|
||||
{
|
||||
static const AZ::Crc32 NetDrillMsg_RequestDrillerEnum = AZ_CRC("NetDrillMsg_RequestEnum", 0x517cca25);
|
||||
static const AZ::Crc32 NetDrillMsg_RequestStartSession = AZ_CRC("NetDrillMsg_RequestStartSession", 0x5238b5fe);
|
||||
static const AZ::Crc32 NetDrillMsg_RequestStopSession = AZ_CRC("NetDrillMsg_RequestStopSession", 0x1abe6888);
|
||||
static const AZ::Crc32 NetDrillMsg_DrillerEnum = AZ_CRC("NetDrillMsg_Enum", 0x3d0a0f76);
|
||||
};
|
||||
|
||||
struct NetDrillerStartSessionRequest
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerStartSessionRequest, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerStartSessionRequest, "{FF899D61-A445-44B5-9B67-8319ACC8BB06}");
|
||||
|
||||
NetDrillerStartSessionRequest()
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession) {}
|
||||
|
||||
// TODO: Replace this with the DrillerListType from driller.h
|
||||
DrillerListType m_drillerIds;
|
||||
AZ::u64 m_sessionId;
|
||||
};
|
||||
|
||||
struct NetDrillerStopSessionRequest
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerStopSessionRequest, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerStopSessionRequest, "{BCC6524F-287F-48D2-A21A-029215DB24DD}");
|
||||
|
||||
NetDrillerStopSessionRequest(AZ::u64 sessionId = 0)
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession)
|
||||
, m_sessionId(sessionId) {}
|
||||
|
||||
AZ::u64 m_sessionId;
|
||||
};
|
||||
|
||||
struct NetDrillerEnumeration
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerEnumeration, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerEnumeration, "{60E5BED2-F492-4A55-8EF6-2628CD390991}");
|
||||
|
||||
NetDrillerEnumeration()
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum) {}
|
||||
|
||||
DrillerInfoListType m_enumeration;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerRemoteSession
|
||||
//---------------------------------------------------------------------
|
||||
DrillerRemoteSession::DrillerRemoteSession()
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
: m_decompressor(&AZ::AllocatorInstance<AZ::OSAllocator>::Get())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
DrillerRemoteSession::~DrillerRemoteSession()
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::StartDrilling(const DrillerListType& drillers, const char* captureFile)
|
||||
{
|
||||
if (captureFile)
|
||||
{
|
||||
m_captureFile.Open(captureFile, AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
AZ_Warning("DrillerRemoteSession", m_captureFile.IsOpen(), "Failed to open %s. Driller data will not be saved.", captureFile);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StartDecompressor();
|
||||
#endif
|
||||
BusConnect(static_cast<AZ::u64>(reinterpret_cast<size_t>(this)));
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, StartRemoteDrillerSession, drillers, this);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::StopDrilling()
|
||||
{
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, StopRemoteDrillerSession, static_cast<AZ::u64>(reinterpret_cast<size_t>(this)));
|
||||
BusDisconnect();
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
if (m_decompressor.IsDecompressorStarted())
|
||||
{
|
||||
m_decompressor.StopDecompressor();
|
||||
}
|
||||
#endif
|
||||
|
||||
m_captureFile.Close();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::LoadCaptureData(const char* fileName)
|
||||
{
|
||||
m_captureFile.Open(fileName, AZ::IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
AZ_Warning("DrillerRemoteSession", m_captureFile.IsOpen(), "Failed to open %s. No driller data could be loaded.", fileName);
|
||||
if (m_captureFile.IsOpen())
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StartDecompressor();
|
||||
#endif
|
||||
AZ::IO::SystemFile::SizeType bytesRemaining = m_captureFile.Length();
|
||||
AZ::IO::SystemFile::SizeType maxReadChunkSize = 1024 * 1024;
|
||||
AZStd::vector<char> readBuffer;
|
||||
readBuffer.resize_no_construct(static_cast<size_t>(maxReadChunkSize));
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
AZ::IO::SystemFile::SizeType bytesToRead = bytesRemaining < maxReadChunkSize ? bytesRemaining : maxReadChunkSize;
|
||||
if (m_captureFile.Read(bytesToRead, readBuffer.data()) != bytesToRead)
|
||||
{
|
||||
AZ_Warning("DrillerRemoteSession", false, "Failed reading driller data. No more driller data can be read.");
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
Decompress(readBuffer.data(), static_cast<size_t>(bytesToRead));
|
||||
ProcessIncomingDrillerData(fileName, m_uncompressedMsgBuffer.data(), m_uncompressedMsgBuffer.size());
|
||||
#else
|
||||
ProcessIncomingDrillerData(fileName, readBuffer.data(), readBuffer.size());
|
||||
#endif
|
||||
bytesRemaining -= bytesToRead;
|
||||
}
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StopDecompressor();
|
||||
#endif
|
||||
m_captureFile.Close();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::OnReceivedMsg(TmMsgPtr msg)
|
||||
{
|
||||
AZ_Assert(msg->GetCustomBlob(), "Missing driller frame data!");
|
||||
|
||||
if (msg->GetCustomBlobSize() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_captureFile.IsOpen())
|
||||
{
|
||||
if (m_captureFile.Write(msg->GetCustomBlob(), msg->GetCustomBlobSize()) != msg->GetCustomBlobSize())
|
||||
{
|
||||
AZ_Warning("DrillerRemoteSession", false, "Failed writing capture data to %s, no more data will be written out.", m_captureFile.Name());
|
||||
m_captureFile.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
Decompress(msg->GetCustomBlob(), msg->GetCustomBlobSize());
|
||||
ProcessIncomingDrillerData(m_captureFile.Name(),m_uncompressedMsgBuffer.data(), m_uncompressedMsgBuffer.size());
|
||||
#else
|
||||
ProcessIncomingDrillerData(m_captureFile.Name(),msg->GetCustomBlob(), msg->GetCustomBlobSize());
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::Decompress(const void* compressedBuffer, size_t compressedBufferSize)
|
||||
{
|
||||
m_uncompressedMsgBuffer.clear();
|
||||
if (m_uncompressedMsgBuffer.capacity() < compressedBufferSize * 10)
|
||||
{
|
||||
m_uncompressedMsgBuffer.reserve(compressedBufferSize * 10);
|
||||
}
|
||||
#if defined(ENABLE_COMPRESSION_FOR_REMOTE_DRILLER)
|
||||
unsigned int compressedBytesRemaining = static_cast<unsigned int>(compressedBufferSize);
|
||||
unsigned int decompressedBytes = 0;
|
||||
while (compressedBytesRemaining > 0)
|
||||
{
|
||||
unsigned int uncompressedBytes = c_decompressionBufferSize;
|
||||
unsigned int bytesConsumed = m_decompressor.Decompress(reinterpret_cast<const char*>(compressedBuffer) + decompressedBytes, compressedBytesRemaining, m_decompressionBuffer, uncompressedBytes);
|
||||
decompressedBytes += bytesConsumed;
|
||||
compressedBytesRemaining -= bytesConsumed;
|
||||
m_uncompressedMsgBuffer.insert(m_uncompressedMsgBuffer.end(), &m_decompressionBuffer[0], &m_decompressionBuffer[uncompressedBytes]);
|
||||
}
|
||||
#else
|
||||
m_uncompressedMsgBuffer.insert(m_uncompressedMsgBuffer.end(), &((char*)compressedBuffer)[0], &((char*)compressedBuffer)[compressedBufferSize]);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerNetSessionStream
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
* Represents a driller session on the target machine.
|
||||
* It is responsible for listening for driller events and forwarding
|
||||
* them to the console machine.
|
||||
*/
|
||||
class DrillerNetSessionStream
|
||||
: public AZ::Debug::DrillerOutputStream
|
||||
, AZ::SystemTickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerNetSessionStream, AZ::OSAllocator, 0);
|
||||
|
||||
DrillerNetSessionStream(AZ::u64 sessionId);
|
||||
~DrillerNetSessionStream();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerOutputStream
|
||||
//---------------------------------------------------------------------
|
||||
virtual void WriteBinary(const void* data, unsigned int dataSize);
|
||||
virtual void OnEndOfFrame();
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// AZ::SystemTickBus
|
||||
//---------------------------------------------------------------------
|
||||
void OnSystemTick() override;
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static const size_t c_defaultUncompressedBufferSize = 256 * 1024;
|
||||
static const size_t c_defaultCompressedBufferSize = 32 * 1024;
|
||||
static const size_t c_bufferCount = 2;
|
||||
|
||||
AZ::Debug::DrillerSession* m_session;
|
||||
AZ::u64 m_sessionId;
|
||||
TargetInfo m_requestor;
|
||||
size_t m_activeBuffer;
|
||||
AZStd::vector<char, AZ::OSStdAllocator> m_uncompressedBuffer[c_bufferCount];
|
||||
AZStd::vector<char, AZ::OSStdAllocator> m_compressedBuffer[c_bufferCount];
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Compression
|
||||
AZ::ZLib m_compressor;
|
||||
AZStd::fixed_vector<char, c_defaultCompressedBufferSize> m_compressionBuffer;
|
||||
#endif
|
||||
|
||||
// String Pooling
|
||||
AZ::Debug::DrillerDefaultStringPool m_stringPool;
|
||||
|
||||
// TEMP Debug
|
||||
//AZ::IO::SystemFile m_file;
|
||||
};
|
||||
|
||||
DrillerNetSessionStream::DrillerNetSessionStream(AZ::u64 sessionId)
|
||||
: m_session(NULL)
|
||||
, m_sessionId(sessionId)
|
||||
, m_activeBuffer(0)
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
, m_compressor(&AZ::AllocatorInstance<AZ::OSAllocator>::Get())
|
||||
#endif
|
||||
{
|
||||
for (size_t i = 0; i < c_bufferCount; ++i)
|
||||
{
|
||||
m_uncompressedBuffer[i].reserve(c_defaultUncompressedBufferSize);
|
||||
m_compressedBuffer[i].reserve(c_defaultCompressedBufferSize);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Level 3 compression seems to give pretty good compression at decent speed.
|
||||
// Speed is paramount for us because initial driller packets can be huge and
|
||||
// we need to be able to compress the data within the driller report call
|
||||
// without blocking for too long.
|
||||
m_compressor.StartCompressor(3);
|
||||
#endif
|
||||
|
||||
SetStringPool(&m_stringPool);
|
||||
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
DrillerNetSessionStream::~DrillerNetSessionStream()
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_compressor.StopCompressor();
|
||||
#endif
|
||||
|
||||
// Debug
|
||||
//m_file.Close();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::WriteBinary(const void* data, unsigned int dataSize)
|
||||
{
|
||||
size_t activeBuffer = m_activeBuffer;
|
||||
|
||||
if (dataSize > 0)
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Only do the compression when the buffer is full so we don't run the compression all the time
|
||||
if (m_uncompressedBuffer[activeBuffer].size() + dataSize > c_defaultUncompressedBufferSize)
|
||||
{
|
||||
// compress
|
||||
unsigned int curDataSize = static_cast<unsigned int>(m_uncompressedBuffer[activeBuffer].size());
|
||||
unsigned int remaining = curDataSize;
|
||||
while (remaining > 0)
|
||||
{
|
||||
unsigned int processedBytes = curDataSize - remaining;
|
||||
unsigned int compressedBytes = m_compressor.Compress(m_uncompressedBuffer[activeBuffer].data() + processedBytes, remaining, m_compressionBuffer.data(), static_cast<unsigned int>(c_defaultCompressedBufferSize));
|
||||
if (compressedBytes > 0)
|
||||
{
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), m_compressionBuffer.data(), m_compressionBuffer.data() + compressedBytes);
|
||||
}
|
||||
}
|
||||
m_uncompressedBuffer[activeBuffer].clear();
|
||||
}
|
||||
|
||||
m_uncompressedBuffer[activeBuffer].insert(m_uncompressedBuffer[activeBuffer].end(), reinterpret_cast<const char*>(data), reinterpret_cast<const char*>(data) + dataSize);
|
||||
#else
|
||||
// Since we are not compressing, transfer the input directly into our compressed buffer
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), reinterpret_cast<const char*>(data), reinterpret_cast<const char*>(data) + dataSize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::OnEndOfFrame()
|
||||
{
|
||||
size_t activeBuffer = m_activeBuffer;
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Write whatever data has not yet been compressed and flush the compressor
|
||||
unsigned int curDataSize = static_cast<unsigned int>(m_uncompressedBuffer[activeBuffer].size());
|
||||
unsigned int remaining = curDataSize;
|
||||
unsigned int compressedBytes = 0;
|
||||
do
|
||||
{
|
||||
unsigned int processedBytes = curDataSize - remaining;
|
||||
compressedBytes = m_compressor.Compress(m_uncompressedBuffer[activeBuffer].data() + processedBytes, remaining, m_compressionBuffer.data(), static_cast<unsigned int>(c_defaultCompressedBufferSize), AZ::ZLib::FT_SYNC_FLUSH);
|
||||
if (compressedBytes > 0)
|
||||
{
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), m_compressionBuffer.data(), m_compressionBuffer.data() + compressedBytes);
|
||||
}
|
||||
} while (compressedBytes > 0 || remaining > 0);
|
||||
#endif
|
||||
|
||||
m_activeBuffer = (activeBuffer + 1) % 2; // switch buffers
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::OnSystemTick()
|
||||
{
|
||||
// The buffer index we want to send is the one we wrote to in the previous frame.
|
||||
size_t bufferIndex = (m_activeBuffer + 1) % 2;
|
||||
|
||||
if (m_compressedBuffer[bufferIndex].empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TmMsg msg(m_sessionId);
|
||||
|
||||
msg.AddCustomBlob(m_compressedBuffer[bufferIndex].data(), m_compressedBuffer[bufferIndex].size());
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_requestor, msg);
|
||||
|
||||
|
||||
// Debug
|
||||
//if (!m_file.IsOpen())
|
||||
//{
|
||||
// AZStd::string filename = AZStd::string::format("localdrill_%llu", m_sessionId);
|
||||
// m_file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
//}
|
||||
//m_file.Write(msg.GetCustomBlob(), msg.GetCustomBlobSize());
|
||||
|
||||
// Reset buffers
|
||||
m_uncompressedBuffer[bufferIndex].clear();
|
||||
m_compressedBuffer[bufferIndex].clear();
|
||||
|
||||
// Buffers may grow during exceptional circumstances. Re-shrink them to their default sizes
|
||||
// so we don't keep holding on to the memory.
|
||||
m_uncompressedBuffer[bufferIndex].reserve(c_defaultUncompressedBufferSize);
|
||||
m_compressedBuffer[bufferIndex].reserve(c_defaultCompressedBufferSize);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerNetworkAgent
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Init()
|
||||
{
|
||||
m_cbDrillerEnumRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerEnum, this, AZStd::placeholders::_1));
|
||||
m_cbDrillerStartRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerStart, this, AZStd::placeholders::_1));
|
||||
m_cbDrillerStopRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerStop, this, AZStd::placeholders::_1));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Activate()
|
||||
{
|
||||
m_cbDrillerEnumRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum);
|
||||
m_cbDrillerStartRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession);
|
||||
m_cbDrillerStopRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession);
|
||||
TargetManagerClient::Bus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Deactivate()
|
||||
{
|
||||
TargetManagerClient::Bus::Handler::BusDisconnect();
|
||||
m_cbDrillerEnumRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum);
|
||||
m_cbDrillerStartRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession);
|
||||
m_cbDrillerStopRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession);
|
||||
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop(m_activeSessions[i]->m_session);
|
||||
}
|
||||
delete m_activeSessions[i];
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("DrillerNetworkAgentService", 0xcd2ab821));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("DrillerNetworkAgentService", 0xcd2ab821));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<DrillerNetworkAgentComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<DrillerNetworkAgentComponent>(
|
||||
"Driller Network Agent", "Runs on the machine being drilled and communicates with tools")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
;
|
||||
}
|
||||
|
||||
ReflectNetDrillerClasses(context);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::TargetLeftNetwork(TargetInfo info)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
for (AZStd::vector<DrillerNetSessionStream*>::iterator it = m_activeSessions.begin(); it != m_activeSessions.end(); )
|
||||
{
|
||||
if ((*it)->m_requestor.GetNetworkId() == info.GetNetworkId())
|
||||
{
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop((*it)->m_session);
|
||||
}
|
||||
delete *it;
|
||||
it = m_activeSessions.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerEnum(TmMsgPtr msg)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (!mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TargetInfo sendTo;
|
||||
EBUS_EVENT_RESULT(sendTo, TargetManager::Bus, GetTargetInfo, msg->GetSenderTargetId());
|
||||
NetDrillerEnumeration drillerEnum;
|
||||
for (int i = 0; i < mgr->GetNumDrillers(); ++i)
|
||||
{
|
||||
AZ::Debug::Driller* driller = mgr->GetDriller(i);
|
||||
AZ_Assert(driller, "DrillerManager returned a NULL driller. This is not legal!");
|
||||
drillerEnum.m_enumeration.push_back();
|
||||
drillerEnum.m_enumeration.back().m_id = driller->GetId();
|
||||
drillerEnum.m_enumeration.back().m_groupName = driller->GroupName();
|
||||
drillerEnum.m_enumeration.back().m_name = driller->GetName();
|
||||
drillerEnum.m_enumeration.back().m_description = driller->GetDescription();
|
||||
}
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, sendTo, drillerEnum);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerStart(TmMsgPtr msg)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (!mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NetDrillerStartSessionRequest* request = azdynamic_cast<NetDrillerStartSessionRequest*>(msg.get());
|
||||
AZ_Assert(request, "Not a NetDrillerStartSessionRequest msg!");
|
||||
AZ::Debug::DrillerManager::DrillerListType drillers;
|
||||
for (size_t i = 0; i < request->m_drillerIds.size(); ++i)
|
||||
{
|
||||
AZ::Debug::DrillerManager::DrillerInfo di;
|
||||
di.id = request->m_drillerIds[i];
|
||||
drillers.push_back(di);
|
||||
}
|
||||
DrillerNetSessionStream* session = aznew DrillerNetSessionStream(request->m_sessionId);
|
||||
EBUS_EVENT_RESULT(session->m_requestor, TargetManager::Bus, GetTargetInfo, msg->GetSenderTargetId());
|
||||
m_activeSessions.push_back(session);
|
||||
session->m_session = mgr->Start(*session, drillers);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerStop(TmMsgPtr msg)
|
||||
{
|
||||
NetDrillerStopSessionRequest* request = azdynamic_cast<NetDrillerStopSessionRequest*>(msg.get());
|
||||
for (AZStd::vector<DrillerNetSessionStream*>::iterator it = m_activeSessions.begin(); it != m_activeSessions.end(); ++it)
|
||||
{
|
||||
if ((*it)->m_sessionId == request->m_sessionId)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop((*it)->m_session);
|
||||
}
|
||||
delete *it;
|
||||
m_activeSessions.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerRemoteConsole
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Init()
|
||||
{
|
||||
m_cbDrillerEnum = TmMsgCallback(AZStd::bind(&DrillerNetworkConsoleComponent::OnReceivedDrillerEnum, this, AZStd::placeholders::_1));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Activate()
|
||||
{
|
||||
m_cbDrillerEnum.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum);
|
||||
DrillerNetworkConsoleCommandBus::Handler::BusConnect();
|
||||
TargetManagerClient::Bus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Deactivate()
|
||||
{
|
||||
TargetManagerClient::Bus::Handler::BusDisconnect();
|
||||
DrillerNetworkConsoleCommandBus::Handler::BusDisconnect();
|
||||
m_cbDrillerEnum.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum);
|
||||
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i]))));
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("DrillerNetworkConsoleService", 0x2286125d));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("DrillerNetworkConsoleService", 0x2286125d));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DrillerNetworkConsoleComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<DrillerNetworkConsoleComponent>(
|
||||
"Driller Network Console", "Runs on the tool machine and is responsible for communications with the DrillerNetworkAgent")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
;
|
||||
}
|
||||
|
||||
ReflectNetDrillerClasses(context);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::EnumerateAvailableDrillers()
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler)
|
||||
{
|
||||
NetDrillerStartSessionRequest request;
|
||||
request.m_drillerIds = drillers;
|
||||
request.m_sessionId = static_cast<AZ::u64>(reinterpret_cast<size_t>(handler));
|
||||
m_activeSessions.push_back(handler);
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, request);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::StopRemoteDrillerSession(AZ::u64 sessionId)
|
||||
{
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
if (sessionId == static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i])))
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(sessionId));
|
||||
m_activeSessions[i] = m_activeSessions.back();
|
||||
m_activeSessions.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::DesiredTargetConnected(bool connected)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
EBUS_EVENT_RESULT(m_curTarget, TargetManager::Bus, GetDesiredTarget);
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, EnumerateAvailableDrillers);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, DrillerInfoListType());
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::DesiredTargetChanged(AZ::u32 newTargetID, AZ::u32 oldTargetID)
|
||||
{
|
||||
(void)oldTargetID;
|
||||
(void)newTargetID;
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, DrillerInfoListType());
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i]))));
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::OnReceivedDrillerEnum(TmMsgPtr msg)
|
||||
{
|
||||
NetDrillerEnumeration* drillerEnum = azdynamic_cast<NetDrillerEnumeration*>(msg.get());
|
||||
AZ_Assert(drillerEnum, "No NetDrillerEnumeration message!");
|
||||
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, drillerEnum->m_enumeration);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// ReflectNetDrillerClasses
|
||||
//---------------------------------------------------------------------
|
||||
void ReflectNetDrillerClasses(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
// Assume no one else will register our classes.
|
||||
if (serialize->FindClassData(DrillerInfo::RTTI_Type()) == nullptr)
|
||||
{
|
||||
serialize->Class<DrillerInfo>()
|
||||
->Field("Id", &DrillerInfo::m_id)
|
||||
->Field("GroupName", &DrillerInfo::m_groupName)
|
||||
->Field("Name", &DrillerInfo::m_name)
|
||||
->Field("Description", &DrillerInfo::m_description);
|
||||
serialize->Class<NetDrillerStartSessionRequest, TmMsg>()
|
||||
->Field("DrillerIds", &NetDrillerStartSessionRequest::m_drillerIds)
|
||||
->Field("SessionId", &NetDrillerStartSessionRequest::m_sessionId);
|
||||
serialize->Class<NetDrillerStopSessionRequest, TmMsg>()
|
||||
->Field("SessionId", &NetDrillerStopSessionRequest::m_sessionId);
|
||||
serialize->Class<NetDrillerEnumeration, TmMsg>()
|
||||
->Field("Enumeration", &NetDrillerEnumeration::m_enumeration);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
} // namespace AzFramework
|
||||
@@ -1,217 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
#define AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Compression/Compression.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Driller/DrillerConsoleAPI.h>
|
||||
#include <AzFramework/TargetManagement/TargetManagementAPI.h>
|
||||
|
||||
//#define ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
struct ClassDataReflection;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/**
|
||||
* Represents a remote driller session on the tool machine.
|
||||
* It is responsible for receiving and processing remote driller data.
|
||||
* Driller clients should derive from this class and implement the virtual interfaces.
|
||||
*/
|
||||
class DrillerRemoteSession
|
||||
: public TmMsgBus::Handler
|
||||
{
|
||||
public:
|
||||
DrillerRemoteSession();
|
||||
~DrillerRemoteSession();
|
||||
|
||||
// Called when new driller data arrives
|
||||
virtual void ProcessIncomingDrillerData(const char* streamIdentifier, const void* data, size_t dataSize) = 0;
|
||||
// Called when the connection to the driller is lost. The session should be deleted in response to this message
|
||||
virtual void OnDrillerConnectionLost() = 0;
|
||||
|
||||
// Start drilling the selected drillers as part of this session
|
||||
void StartDrilling(const DrillerListType& drillers, const char* captureFile);
|
||||
// Stop this drill session
|
||||
void StopDrilling();
|
||||
|
||||
// Replay a previously captured driller session from file
|
||||
void LoadCaptureData(const char* fileName);
|
||||
|
||||
protected:
|
||||
//---------------------------------------------------------------------
|
||||
// TmMsgBus
|
||||
//---------------------------------------------------------------------
|
||||
virtual void OnReceivedMsg(TmMsgPtr msg);
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Decompress(const void* compressedBuffer, size_t compressedBufferSize);
|
||||
|
||||
static const AZ::u32 c_decompressionBufferSize = 128 * 1024;
|
||||
|
||||
AZStd::vector<char> m_uncompressedMsgBuffer;
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
AZ::ZLib m_decompressor;
|
||||
char m_decompressionBuffer[c_decompressionBufferSize];
|
||||
#endif
|
||||
AZ::IO::SystemFile m_captureFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller clients interested in receiving notification events from the
|
||||
* network console should implement this interface.
|
||||
*/
|
||||
class DrillerNetworkConsoleEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerNetworkConsoleEvents() {}
|
||||
|
||||
// A list of available drillers has been received from the target machine.
|
||||
virtual void OnReceivedDrillerEnumeration(const DrillerInfoListType& availableDrillers) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerNetworkConsoleEvents> DrillerNetworkConsoleEventBus;
|
||||
|
||||
/**
|
||||
* The network driller console implements this interface.
|
||||
* Commands can be sent to the network console through this interface.
|
||||
*/
|
||||
class DrillerNetworkConsoleCommands
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
|
||||
// there's only one driller console instance allowed
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerNetworkConsoleCommands() {}
|
||||
|
||||
// Request an enumeration of available drillers from the target machine
|
||||
virtual void EnumerateAvailableDrillers() = 0;
|
||||
// Start a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler) = 0;
|
||||
// Stop a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StopRemoteDrillerSession(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerNetworkConsoleCommands> DrillerNetworkConsoleCommandBus;
|
||||
|
||||
class DrillerNetSessionStream;
|
||||
|
||||
/**
|
||||
* Runs on the machine being drilled and is responsible for communications
|
||||
* with the DrillerNetworkConsole running on the tool side as well as
|
||||
* creating DrillerNetSessionStreams for each driller session being started.
|
||||
*/
|
||||
class DrillerNetworkAgentComponent
|
||||
: public AZ::Component
|
||||
, public TargetManagerClient::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillerNetworkAgentComponent, "{B587A74D-6190-4149-91CB-0EA69936BD59}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
virtual void Init();
|
||||
virtual void Activate();
|
||||
virtual void Deactivate();
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TargetManagerClient
|
||||
virtual void TargetLeftNetwork(TargetInfo info);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TmMsg handlers
|
||||
virtual void OnRequestDrillerEnum(TmMsgPtr msg);
|
||||
virtual void OnRequestDrillerStart(TmMsgPtr msg);
|
||||
virtual void OnRequestDrillerStop(TmMsgPtr msg);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TmMsgCallback m_cbDrillerEnumRequest;
|
||||
TmMsgCallback m_cbDrillerStartRequest;
|
||||
TmMsgCallback m_cbDrillerStopRequest;
|
||||
|
||||
AZStd::vector<DrillerNetSessionStream*> m_activeSessions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs on the tool machine and is responsible for communications with the
|
||||
* DrillerNetworkAgent.
|
||||
*/
|
||||
class DrillerNetworkConsoleComponent
|
||||
: public AZ::Component
|
||||
, public DrillerNetworkConsoleCommandBus::Handler
|
||||
, public TargetManagerClient::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillerNetworkConsoleComponent, "{78ACADA4-F2C7-4320-8E97-59DD8B9BE33A}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
virtual void Init();
|
||||
virtual void Activate();
|
||||
virtual void Deactivate();
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerNetworkConsoleCommandBus
|
||||
virtual void EnumerateAvailableDrillers();
|
||||
virtual void StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler);
|
||||
virtual void StopRemoteDrillerSession(AZ::u64 sessionId);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TargetManagerClient
|
||||
virtual void DesiredTargetConnected(bool connected);
|
||||
virtual void DesiredTargetChanged(AZ::u32 newTargetID, AZ::u32 oldTargetID);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TmMsg handlers
|
||||
virtual void OnReceivedDrillerEnum(TmMsgPtr msg);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef AZStd::vector<DrillerRemoteSession*> ActiveSessionListType;
|
||||
ActiveSessionListType m_activeSessions;
|
||||
TargetInfo m_curTarget;
|
||||
TmMsgCallback m_cbDrillerEnum;
|
||||
};
|
||||
|
||||
void ReflectNetDrillerClasses(AZ::ReflectContext* context);
|
||||
} // namespace AzFramework
|
||||
|
||||
#endif // AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
#pragma once
|
||||
@@ -16,11 +16,14 @@
|
||||
#ifndef AZFRAMEWORK_ENTITYCONTEXTBUS_H
|
||||
#define AZFRAMEWORK_ENTITYCONTEXTBUS_H
|
||||
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class Entity;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzFramework/Entity/EntityOwnershipServiceBus.h>
|
||||
|
||||
@@ -18,6 +19,8 @@ namespace AZ
|
||||
class Entity;
|
||||
}
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
// Types
|
||||
|
||||
@@ -33,6 +33,8 @@ extern "C" {
|
||||
# include <Lua/lauxlib.h>
|
||||
}
|
||||
|
||||
AZ_DEFINE_BUDGET(Script);
|
||||
|
||||
namespace ScriptComponentCpp
|
||||
{
|
||||
template<typename T>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define AZFRAMEWORK_TARGETMANAGEMENTAPI_H
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
@@ -21,6 +22,8 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
|
||||
+2
@@ -12,6 +12,8 @@
|
||||
#include <AzFramework/Visibility/BoundsBus.h>
|
||||
#include <cstring>
|
||||
|
||||
AZ_DECLARE_BUDGET(AzFramework);
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem()
|
||||
|
||||
@@ -123,11 +123,6 @@ set(FILES
|
||||
Entity/SliceGameEntityOwnershipServiceBus.h
|
||||
Entity/PrefabEntityOwnershipService.h
|
||||
Entity/PrefabEntityOwnershipService.cpp
|
||||
Driller/RemoteDrillerInterface.cpp
|
||||
Driller/RemoteDrillerInterface.h
|
||||
Driller/DrillerConsoleAPI.h
|
||||
Driller/DrillToFileComponent.h
|
||||
Driller/DrillToFileComponent.cpp
|
||||
Components/ComponentAdapter.h
|
||||
Components/ComponentAdapter.inl
|
||||
Components/ComponentAdapterHelpers.h
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzFramework/Driller/DrillToFileComponent.h>
|
||||
#include <GridMate/Drillers/CarrierDriller.h>
|
||||
#include <GridMate/Drillers/ReplicaDriller.h>
|
||||
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
|
||||
@@ -37,12 +35,6 @@ namespace AzGameFramework
|
||||
void GameApplication::StartCommon(AZ::Entity* systemEntity)
|
||||
{
|
||||
AzFramework::Application::StartCommon(systemEntity);
|
||||
|
||||
if (GetDrillerManager())
|
||||
{
|
||||
GetDrillerManager()->Register(aznew GridMate::Debug::CarrierDriller());
|
||||
GetDrillerManager()->Register(aznew GridMate::Debug::ReplicaDriller());
|
||||
}
|
||||
}
|
||||
|
||||
void GameApplication::MergeSettingsToRegistry(AZ::SettingsRegistryInterface& registry)
|
||||
@@ -92,10 +84,6 @@ namespace AzGameFramework
|
||||
components.emplace_back(azrtti_typeid<AzFramework::TargetManagementComponent>());
|
||||
#endif
|
||||
|
||||
// Note that this component is registered by AzFramework.
|
||||
// It must be registered here instead of in the module so that existence of AzFrameworkModule is guaranteed.
|
||||
components.emplace_back(azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>());
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
@@ -104,9 +92,6 @@ namespace AzGameFramework
|
||||
AzFramework::Application::CreateStaticModules(outModules);
|
||||
|
||||
outModules.emplace_back(aznew AzGameFrameworkModule());
|
||||
|
||||
// have to let the metrics system know that it's ok to send back the name of the DrillerNetworkAgentComponent to Amazon as plain text, without hashing
|
||||
EBUS_EVENT(AzFramework::MetricsPlainTextNameRegistrationBus, RegisterForNameSending, AZStd::vector<AZ::Uuid>{ azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>() });
|
||||
}
|
||||
|
||||
void GameApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const
|
||||
|
||||
@@ -7,24 +7,15 @@
|
||||
*/
|
||||
#include <AzGameFramework/AzGameFrameworkModule.h>
|
||||
|
||||
// Component includes
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzFramework/Driller/DrillToFileComponent.h>
|
||||
|
||||
namespace AzGameFramework
|
||||
{
|
||||
AzGameFrameworkModule::AzGameFrameworkModule()
|
||||
: AZ::Module()
|
||||
{
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
AzFramework::DrillToFileComponent::CreateDescriptor(),
|
||||
});
|
||||
}
|
||||
|
||||
AZ::ComponentTypeList AzGameFrameworkModule::GetRequiredSystemComponents() const
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<AzFramework::DrillToFileComponent>(),
|
||||
};
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AZTOOLSFRAMEWORK_TOOLSAPPLICATIONAPI_H
|
||||
#define AZTOOLSFRAMEWORK_TOOLSAPPLICATIONAPI_H
|
||||
|
||||
#include <AzCore/base.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
@@ -1089,4 +1085,5 @@ namespace AzToolsFramework
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#endif // AZTOOLSFRAMEWORK_TOOLSAPPLICATIONAPI_H
|
||||
AZ_DECLARE_BUDGET(AzToolsFramework);
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzToolsFramework);
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
AzToolsFrameworkModule::AzToolsFrameworkModule()
|
||||
|
||||
-6
@@ -35,10 +35,8 @@
|
||||
#include <AzFramework/Asset/AssetCatalogComponent.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Debug/ProfilerDriller.h>
|
||||
|
||||
#ifdef AZ_PLATFORM_WINDOWS
|
||||
#include "shlobj.h"
|
||||
@@ -485,8 +483,6 @@ namespace LegacyFramework
|
||||
void Application::CreateApplicationComponents()
|
||||
{
|
||||
EnsureComponentCreated(AzFramework::TargetManagementComponent::RTTI_Type());
|
||||
EnsureComponentCreated(AzFramework::DrillerNetworkConsoleComponent::RTTI_Type());
|
||||
EnsureComponentCreated(AzFramework::DrillerNetworkAgentComponent::RTTI_Type());
|
||||
}
|
||||
|
||||
void Application::CreateSystemComponents()
|
||||
@@ -507,8 +503,6 @@ namespace LegacyFramework
|
||||
ComponentApplication::RegisterCoreComponents();
|
||||
|
||||
RegisterComponentDescriptor(AzFramework::TargetManagementComponent::CreateDescriptor());
|
||||
RegisterComponentDescriptor(AzFramework::DrillerNetworkConsoleComponent::CreateDescriptor());
|
||||
RegisterComponentDescriptor(AzFramework::DrillerNetworkAgentComponent::CreateDescriptor());
|
||||
RegisterComponentDescriptor(AzToolsFramework::Framework::CreateDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -5,7 +5,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
@@ -14,8 +17,6 @@
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include "PropertyEditorAPI_Internals.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
class QWidget;
|
||||
class QCheckBox;
|
||||
class QLabel;
|
||||
|
||||
+2
@@ -25,6 +25,8 @@ class QColor;
|
||||
class QString;
|
||||
class QPoint;
|
||||
|
||||
AZ_DECLARE_BUDGET(AzToolsFramework);
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Components
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
AZ_DECLARE_BUDGET(AzToolsFramework);
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace UndoSystem
|
||||
|
||||
@@ -1117,7 +1117,6 @@ namespace UnitTest
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
|
||||
@@ -14,6 +15,8 @@
|
||||
#include <GridMate/GridMateEventsBus.h>
|
||||
#include <GridMate/Version.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(GridMate);
|
||||
|
||||
namespace GridMate
|
||||
{
|
||||
class GridMateImpl
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef GM_REPLICADEFS_H
|
||||
#define GM_REPLICADEFS_H
|
||||
|
||||
/// \file ReplicaChunk.h
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace GridMate
|
||||
@@ -80,4 +78,5 @@ namespace GridMate
|
||||
static const ZoneMask ZoneMask_All = (ZoneMask) - 1;
|
||||
} // namespace Gridmate
|
||||
|
||||
#endif // GM_REPLICADEFS_H
|
||||
AZ_DECLARE_BUDGET(GridMate);
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
#include <GridMate/Replica/SystemReplicas.h>
|
||||
#include <GridMate/Replica/Tasks/ReplicaMarshalTasks.h>
|
||||
#include <GridMate/Replica/ReplicaDrillerEvents.h>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
set(FILES
|
||||
test_Main.cpp
|
||||
TestProfiler.cpp
|
||||
Tests.h
|
||||
Session.cpp
|
||||
Serialize.cpp
|
||||
@@ -16,7 +15,6 @@ set(FILES
|
||||
ReplicaSmall.cpp
|
||||
ReplicaMedium.cpp
|
||||
ReplicaBehavior.cpp
|
||||
Replica.cpp
|
||||
StreamSecureSocketDriverTests.cpp
|
||||
StreamSocketDriverTests.cpp
|
||||
CarrierStreamSocketDriverTests.cpp
|
||||
|
||||
@@ -1,67 +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 <AzCore/Debug/Profiler.h>
|
||||
|
||||
#define SUBSYSTEM_DEFINES \
|
||||
X(PROFILE_ANY, "Any") \
|
||||
X(PROFILE_RENDERER, "Renderer") \
|
||||
X(PROFILE_3DENGINE, "3DEngine") \
|
||||
X(PROFILE_PARTICLE, "Particle") \
|
||||
X(PROFILE_AI, "AI") \
|
||||
X(PROFILE_ANIMATION, "Animation") \
|
||||
X(PROFILE_MOVIE, "Movie") \
|
||||
X(PROFILE_ENTITY, "Entity") \
|
||||
X(PROFILE_UI, "UI") \
|
||||
X(PROFILE_NETWORK, "Network") \
|
||||
X(PROFILE_PHYSICS, "Physics") \
|
||||
X(PROFILE_SCRIPT, "Script") \
|
||||
X(PROFILE_SCRIPT_CFUNC, "Script C Functions") \
|
||||
X(PROFILE_AUDIO, "Audio") \
|
||||
X(PROFILE_EDITOR, "Editor") \
|
||||
X(PROFILE_SYSTEM, "System") \
|
||||
X(PROFILE_ACTION, "Action") \
|
||||
X(PROFILE_GAME, "Game") \
|
||||
X(PROFILE_INPUT, "Input") \
|
||||
X(PROFILE_SYNC, "Sync") \
|
||||
X(PROFILE_NETWORK_TRAFFIC, "Network Traffic") \
|
||||
X(PROFILE_DEVICE, "Device")
|
||||
|
||||
#define X(Subsystem, SubsystemName) Subsystem,
|
||||
enum EProfiledSubsystem
|
||||
{
|
||||
SUBSYSTEM_DEFINES
|
||||
PROFILE_LAST_SUBSYSTEM
|
||||
};
|
||||
#undef X
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
|
||||
|
||||
#define FUNCTION_PROFILER_LEGACYONLY(pISystem, subsystem)
|
||||
|
||||
#define FUNCTION_PROFILER(pISystem, subsystem)
|
||||
|
||||
#define FUNCTION_PROFILER_FAST(pISystem, subsystem, bProfileEnabled)
|
||||
|
||||
#define FUNCTION_PROFILER_ALWAYS(pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER_LEGACYONLY(szProfilerName, pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER(szProfilerName, pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER_FAST(szProfilerName, pISystem, subsystem, bProfileEnabled)
|
||||
|
||||
#define FUNCTION_PROFILER_SYS(subsystem)
|
||||
|
||||
#define STALL_PROFILER(cause)
|
||||
|
||||
@@ -1654,11 +1654,4 @@ inline void CryLogAlways(const char* format, ...)
|
||||
}
|
||||
|
||||
#endif // EXCLUDE_NORMAL_LOG
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Additional headers.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#include <FrameProfiler.h>
|
||||
|
||||
#endif // CRYINCLUDE_CRYCOMMON_ISYSTEM_H
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ set(FILES
|
||||
CrySystemBus.h
|
||||
CryTypeInfo.h
|
||||
CryVersion.h
|
||||
FrameProfiler.h
|
||||
HeapAllocator.h
|
||||
LegacyAllocator.cpp
|
||||
LegacyAllocator.h
|
||||
|
||||
@@ -1899,7 +1899,6 @@ static void LogDecompTimer(__int64 nTotalTicks, __int64 nDecompTicks, __int64 nA
|
||||
|
||||
AZStd::string CLocalizedStringsManager::SLocalizedStringEntry::GetTranslatedText(const SLanguage* pLanguage) const
|
||||
{
|
||||
FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_SYSTEM, g_bProfilerEnabled);
|
||||
if ((flags & IS_COMPRESSED) != 0)
|
||||
{
|
||||
#if defined(LOG_DECOMP_TIMES)
|
||||
|
||||
@@ -396,7 +396,6 @@ void CLog::LogV(const ELogType type, [[maybe_unused]]int flags, const char* szFo
|
||||
}
|
||||
}
|
||||
|
||||
FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM);
|
||||
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
||||
|
||||
bool bfile = false, bconsole = false;
|
||||
@@ -1445,8 +1444,6 @@ void CLog::RemoveCallback(ILogCallback* pCallback)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CLog::Update()
|
||||
{
|
||||
FUNCTION_PROFILER_FAST(m_pSystem, PROFILE_SYSTEM, g_bProfilerEnabled);
|
||||
|
||||
if (CryGetCurrentThreadId() == m_nMainThreadId)
|
||||
{
|
||||
if (!m_threadSafeMsgQueue.empty())
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/API/ApplicationAPI_Platform.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
#include <AzCore/Debug/IEventLogger.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
@@ -659,8 +661,6 @@ ISystem* CSystem::GetCrySystem()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CSystem::SleepIfNeeded()
|
||||
{
|
||||
FUNCTION_PROFILER_FAST(this, PROFILE_SYSTEM, g_bProfilerEnabled);
|
||||
|
||||
ITimer* const pTimer = gEnv->pTimer;
|
||||
static bool firstCall = true;
|
||||
|
||||
@@ -738,7 +738,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
_mm_setcsr(_mm_getcsr() & ~0x280 | (g_cvars.sys_float_exceptions > 0 ? 0 : 0x280));
|
||||
#endif //WIN32
|
||||
|
||||
FUNCTION_PROFILER_LEGACYONLY(GetISystem(), PROFILE_SYSTEM);
|
||||
AZ_TRACE_METHOD();
|
||||
|
||||
m_nUpdateCounter++;
|
||||
@@ -832,8 +831,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
//limit frame rate if vsync is turned off
|
||||
//for consoles this is done inside renderthread to be vsync dependent
|
||||
{
|
||||
FRAME_PROFILER_LEGACYONLY("FRAME_CAP", gEnv->pSystem, PROFILE_SYSTEM);
|
||||
AZ_TRACE_METHOD_NAME("FrameLimiter");
|
||||
static ICVar* pSysMaxFPS = NULL;
|
||||
static ICVar* pVSync = NULL;
|
||||
|
||||
@@ -882,7 +879,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
//update console system
|
||||
if (m_env.pConsole)
|
||||
{
|
||||
FRAME_PROFILER("SysUpdate:Console", this, PROFILE_SYSTEM);
|
||||
m_env.pConsole->Update();
|
||||
}
|
||||
|
||||
@@ -898,7 +894,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
|
||||
// Run movie system pre-update
|
||||
if (!bNoUpdate)
|
||||
{
|
||||
FRAME_PROFILER("SysUpdate:UpdateMovieSystem", this, PROFILE_SYSTEM);
|
||||
UpdateMovieSystem(updateFlags, fMovieFrameTime, true);
|
||||
}
|
||||
|
||||
@@ -914,7 +909,6 @@ bool CSystem::UpdatePostTickBus(int updateFlags, int /*nPauseMode*/)
|
||||
if (!m_bNoUpdate)
|
||||
{
|
||||
const float fMovieFrameTime = m_Time.GetFrameTime(ITimer::ETIMER_UI);
|
||||
FRAME_PROFILER("SysUpdate:UpdateMovieSystem", this, PROFILE_SYSTEM);
|
||||
UpdateMovieSystem(updateFlags, fMovieFrameTime, false);
|
||||
}
|
||||
|
||||
@@ -922,7 +916,6 @@ bool CSystem::UpdatePostTickBus(int updateFlags, int /*nPauseMode*/)
|
||||
// Update sound system
|
||||
if (!m_bNoUpdate)
|
||||
{
|
||||
FRAME_PROFILER("SysUpdate:UpdateAudioSystems", this, PROFILE_SYSTEM);
|
||||
UpdateAudioSystems();
|
||||
}
|
||||
|
||||
@@ -949,10 +942,7 @@ bool CSystem::UpdatePostTickBus(int updateFlags, int /*nPauseMode*/)
|
||||
m_updateTimes.push_back(std::make_pair(cur_time, updateTime));
|
||||
}
|
||||
|
||||
{
|
||||
FRAME_PROFILER("SysUpdate - SystemEventDispatcher::Update", this, PROFILE_SYSTEM);
|
||||
m_pSystemEventDispatcher->Update();
|
||||
}
|
||||
m_pSystemEventDispatcher->Update();
|
||||
|
||||
if (!gEnv->IsEditing() && m_eRuntimeState == ESYSTEM_EVENT_LEVEL_GAMEPLAY_START)
|
||||
{
|
||||
@@ -973,8 +963,6 @@ bool CSystem::UpdateLoadtime()
|
||||
|
||||
void CSystem::UpdateAudioSystems()
|
||||
{
|
||||
AZ_TRACE_METHOD();
|
||||
FRAME_PROFILER_LEGACYONLY("SysUpdate:Audio", this, PROFILE_SYSTEM);
|
||||
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::ExternalUpdate);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "CrySystem_precompiled.h"
|
||||
#include "SystemEventDispatcher.h"
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
CSystemEventDispatcher::CSystemEventDispatcher()
|
||||
: m_listeners(0)
|
||||
|
||||
@@ -97,7 +97,6 @@
|
||||
#include <CrySystemBus.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
#include <AzCore/Jobs/JobManagerBus.h>
|
||||
#include <AzFramework/Driller/DrillerConsoleAPI.h>
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <AzCore/Android/Utils.h>
|
||||
@@ -1696,46 +1695,6 @@ void CmdSetAwsLogLevel(IConsoleCmdArgs* pArgs)
|
||||
}
|
||||
}
|
||||
|
||||
void CmdDrillToFile(IConsoleCmdArgs* pArgs)
|
||||
{
|
||||
if (azstricmp(pArgs->GetArg(0), "DrillerStop") == 0)
|
||||
{
|
||||
EBUS_EVENT(AzFramework::DrillerConsoleCommandBus, StopDrillerSession, AZ::Crc32("DefaultDrillerSession"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pArgs->GetArgCount() > 1)
|
||||
{
|
||||
AZ::Debug::DrillerManager::DrillerListType drillersToEnable;
|
||||
for (int iArg = 1; iArg < pArgs->GetArgCount(); ++iArg)
|
||||
{
|
||||
if (azstricmp(pArgs->GetArg(iArg), "Replica") == 0)
|
||||
{
|
||||
drillersToEnable.push_back();
|
||||
drillersToEnable.back().id = AZ::Crc32("ReplicaDriller");
|
||||
}
|
||||
else if (azstricmp(pArgs->GetArg(iArg), "Carrier") == 0)
|
||||
{
|
||||
drillersToEnable.push_back();
|
||||
drillersToEnable.back().id = AZ::Crc32("CarrierDriller");
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways("Driller %s not supported.", pArgs->GetArg(iArg));
|
||||
}
|
||||
}
|
||||
EBUS_EVENT(AzFramework::DrillerConsoleCommandBus, StartDrillerSession, drillersToEnable, AZ::Crc32("DefaultDrillerSession"));
|
||||
}
|
||||
else
|
||||
{
|
||||
CryLogAlways("Syntax: DrillerStart [Driller1] [Driller2] [...]");
|
||||
CryLogAlways("Supported Drillers:");
|
||||
CryLogAlways(" Carrier");
|
||||
CryLogAlways(" Replica");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CSystem::CreateSystemVars()
|
||||
{
|
||||
@@ -2114,9 +2073,6 @@ void CSystem::CreateSystemVars()
|
||||
// By default it is now enabled. Modify system.cfg or game.cfg to disable it
|
||||
REGISTER_INT("sys_enableCanvasEditor", 1, VF_NULL, "Enables the UI Canvas Editor");
|
||||
|
||||
REGISTER_COMMAND_DEV_ONLY("DrillerStart", CmdDrillToFile, VF_DEV_ONLY, "Start a driller capture.");
|
||||
REGISTER_COMMAND_DEV_ONLY("DrillerStop", CmdDrillToFile, VF_DEV_ONLY, "Stop a driller capture.");
|
||||
|
||||
REGISTER_COMMAND("sys_SetLogLevel", CmdSetAwsLogLevel, 0, "Set AWS log level [0 - 6].");
|
||||
}
|
||||
|
||||
|
||||
@@ -172,8 +172,6 @@ CViewSystem::~CViewSystem()
|
||||
//------------------------------------------------------------------------
|
||||
void CViewSystem::Update(float frameTime)
|
||||
{
|
||||
FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION);
|
||||
|
||||
if (gEnv->IsDedicated())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetCatalogComponent.h>
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzFramework/Entity/GameEntityContextComponent.h>
|
||||
#include <AzFramework/FileTag/FileTagComponent.h>
|
||||
#include <AzFramework/Input/System/InputSystemComponent.h>
|
||||
@@ -169,7 +168,6 @@ namespace AssetBundler
|
||||
if (*iter == azrtti_typeid<AzFramework::GameEntityContextComponent>() ||
|
||||
*iter == azrtti_typeid<AzFramework::AzFrameworkConfigurationSystemComponent>() ||
|
||||
*iter == azrtti_typeid<AzFramework::InputSystemComponent>() ||
|
||||
*iter == azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>() ||
|
||||
*iter == azrtti_typeid<AZ::SliceSystemComponent>())
|
||||
{
|
||||
// Asset Bundler does not require the above components to be active
|
||||
|
||||
@@ -371,7 +371,6 @@ namespace AZ::SceneAPI::Containers
|
||||
MOCK_CONST_METHOD0(GetAppRoot, const char*());
|
||||
MOCK_CONST_METHOD0(GetEngineRoot, const char*());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
|
||||
};
|
||||
|
||||
|
||||
@@ -38,34 +38,3 @@ ly_add_target(
|
||||
PRIVATE
|
||||
STANDALONETOOLS_ENABLE_LUA_IDE
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME Profiler APPLICATION
|
||||
NAMESPACE AZ
|
||||
AUTOMOC
|
||||
AUTOUIC
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
standalone_tools_files.cmake
|
||||
profiler_files.cmake
|
||||
Platform/${PAL_PLATFORM_NAME}/profiler_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Source/Editor
|
||||
Source/Driller
|
||||
Source/Driller/Carrier
|
||||
Source/Driller/Profiler
|
||||
Source/Driller/IO
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
AZ::AzToolsFramework
|
||||
AZ::GridMate
|
||||
${additional_dependencies}
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
STANDALONETOOLS_ENABLE_PROFILER
|
||||
)
|
||||
|
||||
@@ -1,84 +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 "AnnotationHeaderView.hxx"
|
||||
#include "AnnotationsDataView.hxx"
|
||||
#include "Annotations.hxx"
|
||||
#include <QtWidgets/QGridLayout>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
static const int k_contractedSize = 20;
|
||||
static const int k_textWidth = 153;
|
||||
|
||||
AnnotationHeaderView::AnnotationHeaderView(AnnotationsProvider* ptrAnnotations, QWidget* parent, Qt::WindowFlags flags)
|
||||
: QWidget(parent, flags)
|
||||
, m_ptrAnnotations(ptrAnnotations)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
m_State.m_EndFrame = -1;
|
||||
m_State.m_FramesInView = 10;
|
||||
m_State.m_FrameOffset = 0;
|
||||
|
||||
annotationDataView->RegisterAnnotationHeaderView(this, m_ptrAnnotations);
|
||||
annotationDataView->setAutoFillBackground(true);
|
||||
|
||||
connect(configureAnnotations, SIGNAL(pressed()), this, SIGNAL(OnOptionsClick()));
|
||||
connect(annotationDataView, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)), this, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)));
|
||||
connect(annotationDataView, SIGNAL(InformOfClickAnnotation(const Annotation&)), this, SIGNAL(InformOfClickAnnotation(const Annotation&)));
|
||||
connect(m_ptrAnnotations, SIGNAL(AnnotationDataInvalidated()), this, SLOT(RefreshView()));
|
||||
|
||||
annotationDataView->update();
|
||||
|
||||
QSize size = annotationDataView->size();
|
||||
int nextHeight = size.height();
|
||||
|
||||
(void)nextHeight;
|
||||
}
|
||||
|
||||
QSize AnnotationHeaderView::sizeHint() const
|
||||
{
|
||||
return QSize(0, k_contractedSize);
|
||||
}
|
||||
|
||||
|
||||
AnnotationHeaderView::~AnnotationHeaderView()
|
||||
{
|
||||
}
|
||||
|
||||
void AnnotationHeaderView::RefreshView()
|
||||
{
|
||||
annotationDataView->update();
|
||||
}
|
||||
|
||||
void AnnotationHeaderView::SetEndFrame(FrameNumberType frameNum)
|
||||
{
|
||||
QSize size = annotationDataView->size();
|
||||
int nextHeight = size.height();
|
||||
|
||||
(void)nextHeight;
|
||||
|
||||
m_State.m_EndFrame = frameNum;
|
||||
annotationDataView->update();
|
||||
}
|
||||
|
||||
void AnnotationHeaderView::SetSliderOffset(FrameNumberType frameNum)
|
||||
{
|
||||
m_State.m_FrameOffset = frameNum;
|
||||
annotationDataView->update();
|
||||
}
|
||||
|
||||
void AnnotationHeaderView::SetDataPointsInView(int count)
|
||||
{
|
||||
m_State.m_FramesInView = count;
|
||||
annotationDataView->update();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_AnnotationHeaderView.cpp>
|
||||
@@ -1,74 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANNOTATION_HEADER_VIEW_HXX
|
||||
#define ANNOTATION_HEADER_VIEW_HXX
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <Source/Driller/Annotations/ui_AnnotationHeaderView.h>
|
||||
#include <Source/Driller/DrillerNetworkMessages.h>
|
||||
#include <Source/Driller/DrillerDataTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
class AnnotationsProvider;
|
||||
class AnnotationsDataView;
|
||||
class Annotation;
|
||||
|
||||
/** The annotation header view runs along the top of the channels, and shows annotation blips that can be hovered over.
|
||||
* this gives nice hit boxes for clicking that are not a sliver thick.
|
||||
*/
|
||||
|
||||
class AnnotationHeaderView : public QWidget, private Ui::AnnotationHeaderView
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AnnotationHeaderView,AZ::SystemAllocator,0);
|
||||
AnnotationHeaderView(AnnotationsProvider* ptrAnnotations, QWidget* parent = NULL, Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
virtual ~AnnotationHeaderView(void);
|
||||
|
||||
struct HeaderViewState
|
||||
{
|
||||
int m_EndFrame;
|
||||
int m_FramesInView;
|
||||
int m_FrameOffset;
|
||||
};
|
||||
|
||||
const HeaderViewState& GetState() { return m_State; }
|
||||
|
||||
void SetDataPointsInView( int count );
|
||||
void SetEndFrame( FrameNumberType frame );
|
||||
void SetSliderOffset( FrameNumberType frame );
|
||||
|
||||
signals:
|
||||
void OnOptionsClick();
|
||||
void InformOfMouseOverAnnotation(const Annotation& annotation);
|
||||
void InformOfClickAnnotation(const Annotation& annotation);
|
||||
public slots:
|
||||
void RefreshView();
|
||||
|
||||
private:
|
||||
HeaderViewState m_State;
|
||||
|
||||
AnnotationsProvider *m_ptrAnnotations;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ANNOTATION_HEADER_VIEW_HXX
|
||||
@@ -1,178 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AnnotationHeaderView</class>
|
||||
<widget class="QWidget" name="AnnotationHeaderView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1023</width>
|
||||
<height>38</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="annotationBackground">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="configureAnnotations">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Configure which messages are annotated on the display</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Configure Annotations</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../../Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Resources/sharedResources.qrc">
|
||||
<normaloff>:/driller/settings_icon</normaloff>:/driller/settings_icon</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Driller::AnnotationsDataView" name="annotationDataView" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Driller::AnnotationsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Source/Driller/Annotations/AnnotationsDataView.hxx</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../../../Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Resources/sharedResources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,405 +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 "Annotations.hxx"
|
||||
#include <Source/Driller/Workspaces/Workspace.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/UserSettings/UserSettings.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
|
||||
#include <QColor>
|
||||
#include <QRgb>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
// stores the settings that are saved into the file and transported from user to user to accompany drill files.
|
||||
// as always, this is just a dumb container and does not need encapsulation
|
||||
class AnnotationWorkspaceSettings
|
||||
: public AZ::UserSettings
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AnnotationWorkspaceSettings, "{431EFFCF-C3C5-4BB3-8246-E452E11D4FF8}", AZ::UserSettings);
|
||||
AZ_CLASS_ALLOCATOR(AnnotationWorkspaceSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
ChannelContainer m_ActiveAnnotationChannels;
|
||||
ChannelCRCContainer m_ActiveAnnotationChannelCRCs;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<AnnotationWorkspaceSettings>()
|
||||
->Version(2)
|
||||
->Field("m_ActiveAnnotationChannels", &AnnotationWorkspaceSettings::m_ActiveAnnotationChannels)
|
||||
->Field("m_ActiveAnnotationChannelCRCs", &AnnotationWorkspaceSettings::m_ActiveAnnotationChannelCRCs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// stores the data that goes with the user preferences, even without a workspace file
|
||||
// mainly gui stuff...
|
||||
// as always, this is just a dumb container and does not need encapsulation
|
||||
class AnnotationUserSettings
|
||||
: public AZ::UserSettings
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AnnotationUserSettings, "{D3584846-0574-4B63-9693-4F3265CDE16D}", AZ::UserSettings);
|
||||
AZ_CLASS_ALLOCATOR(AnnotationUserSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
ChannelContainer m_KnownAnnotationChannels; // keeps track of all annotation channels ever seen
|
||||
AZStd::unordered_map<AZ::u32, AZ::u32> m_customizedColors;
|
||||
|
||||
AZ::u32 GetRGBAColorForChannel(AZ::u32 channelNameCRC)
|
||||
{
|
||||
auto found = m_customizedColors.find(channelNameCRC);
|
||||
if (found != m_customizedColors.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
|
||||
AZ::u32 num_different_colors = 7;
|
||||
QColor col;
|
||||
float sat = .9f;
|
||||
float val = .9f;
|
||||
col.setHsvF((float)(channelNameCRC % num_different_colors) / (float(num_different_colors)), sat, val);
|
||||
QRgb rgbColor = col.rgba();
|
||||
return rgbColor;
|
||||
}
|
||||
|
||||
void SetRGBAColorForChannel(AZ::u32 channelNameCRC, AZ::u32 rgbaColor)
|
||||
{
|
||||
m_customizedColors[channelNameCRC] = rgbaColor;
|
||||
}
|
||||
|
||||
void ResetColorForChannel(AZ::u32 channelNameCRC)
|
||||
{
|
||||
m_customizedColors.erase(channelNameCRC);
|
||||
}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<AnnotationUserSettings>()
|
||||
->Version(1)
|
||||
->Field("m_KnownAnnotationChannels", &AnnotationUserSettings::m_KnownAnnotationChannels)
|
||||
->Field("m_customizedColors", &AnnotationUserSettings::m_customizedColors);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AnnotationsProvider::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AnnotationWorkspaceSettings::Reflect(context);
|
||||
AnnotationUserSettings::Reflect(context);
|
||||
}
|
||||
|
||||
Annotation::Annotation()
|
||||
{
|
||||
m_ChannelCRC = 0;
|
||||
m_eventIndex = 0;
|
||||
m_frameIndex = 0;
|
||||
}
|
||||
|
||||
Annotation::Annotation(AZ::s64 eventID, FrameNumberType frame, const char* text, const char* channel)
|
||||
{
|
||||
m_eventIndex = eventID;
|
||||
m_frameIndex = frame;
|
||||
m_text = text;
|
||||
m_channel = channel;
|
||||
m_ChannelCRC = AZ::Crc32(m_channel.c_str());
|
||||
}
|
||||
|
||||
Annotation::Annotation(const Annotation& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Annotation::Annotation(Annotation&& other)
|
||||
{
|
||||
*this = AZStd::move(other);
|
||||
}
|
||||
|
||||
Annotation& Annotation::operator=(Annotation&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_eventIndex = other.m_eventIndex;
|
||||
m_frameIndex = other.m_frameIndex;
|
||||
m_text = AZStd::move(other.m_text);
|
||||
m_channel = AZStd::move(other.m_channel);
|
||||
m_ChannelCRC = other.m_ChannelCRC;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Annotation& Annotation::operator=(const Annotation& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
m_eventIndex = other.m_eventIndex;
|
||||
m_frameIndex = other.m_frameIndex;
|
||||
m_text = other.m_text;
|
||||
m_channel = other.m_channel;
|
||||
m_ChannelCRC = other.m_ChannelCRC;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AnnotationsProvider::AnnotationsProvider(QObject* pParent)
|
||||
: QObject(pParent)
|
||||
{
|
||||
m_bVectorDirty = false;
|
||||
|
||||
/// load user settings and workspace settings from usersettings component to persist state
|
||||
|
||||
m_ptrUserSettings = AZ::UserSettings::CreateFind<AnnotationUserSettings>(AZ_CRC("ANNOT_USERSETTINGS", 0x3ddaa4f1), AZ::UserSettings::CT_GLOBAL);
|
||||
m_ptrWorkspaceSettings = AZ::UserSettings::CreateFind<AnnotationWorkspaceSettings>(AZ_CRC("ANNOT_WORKSPACESETTINGS", 0xf7ca8dd3), AZ::UserSettings::CT_GLOBAL);
|
||||
}
|
||||
|
||||
AnnotationsProvider::~AnnotationsProvider()
|
||||
{
|
||||
AZ::UserSettings::Release(m_ptrUserSettings);
|
||||
AZ::UserSettings::Release(m_ptrWorkspaceSettings);
|
||||
}
|
||||
|
||||
|
||||
void AnnotationsProvider::LoadSettingsFromWorkspace(WorkspaceSettingsProvider* ptrProvider)
|
||||
{
|
||||
AnnotationWorkspaceSettings* rawPtr = ptrProvider->FindSetting<AnnotationWorkspaceSettings>(AZ_CRC("ANNOTATIONWORKSPACE", 0x28319f66));
|
||||
if (rawPtr)
|
||||
{
|
||||
m_ptrWorkspaceSettings->m_ActiveAnnotationChannels = rawPtr->m_ActiveAnnotationChannels;
|
||||
m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs = rawPtr->m_ActiveAnnotationChannelCRCs;
|
||||
|
||||
// aggregate missing channels:
|
||||
for (auto it = m_ptrWorkspaceSettings->m_ActiveAnnotationChannels.begin(); it != m_ptrWorkspaceSettings->m_ActiveAnnotationChannels.end(); ++it)
|
||||
{
|
||||
NotifyOfChannelExistence(it->c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsProvider::SaveSettingsToWorkspace(WorkspaceSettingsProvider* ptrProvider)
|
||||
{
|
||||
AnnotationWorkspaceSettings* rawPtr = ptrProvider->CreateSetting<AnnotationWorkspaceSettings>(AZ_CRC("ANNOTATIONWORKSPACE", 0x28319f66));
|
||||
rawPtr->m_ActiveAnnotationChannels = m_ptrWorkspaceSettings->m_ActiveAnnotationChannels;
|
||||
rawPtr->m_ActiveAnnotationChannelCRCs = m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs;
|
||||
}
|
||||
|
||||
// returns the end of the vector (ie, the invalid iterator)
|
||||
AnnotationsProvider::ConstAnnotationIterator AnnotationsProvider::GetEnd() const
|
||||
{
|
||||
AZ_Assert(!m_bVectorDirty, "You may not interrogate the annotations provider before it is finalized");
|
||||
|
||||
return m_currentAnnotations.end();
|
||||
}
|
||||
|
||||
// returns iterator to the first annotation thats on the frame given (or the end iterator)
|
||||
AnnotationsProvider::ConstAnnotationIterator AnnotationsProvider::GetFirstAnnotationForFrame(FrameNumberType frameIndex) const
|
||||
{
|
||||
AZ_Assert(!m_bVectorDirty, "You may not interrogate the annotations provider before it is finalized");
|
||||
|
||||
// do we have annotations for that framE?
|
||||
FrameIndexToCurrentMap::const_iterator it = m_frameToIndex.find(frameIndex);
|
||||
if (it == m_frameToIndex.end())
|
||||
{
|
||||
return GetEnd();
|
||||
}
|
||||
|
||||
return m_currentAnnotations.begin() + it->second;
|
||||
}
|
||||
|
||||
// returns iterator to the first annotation that is foer that event # (or the end iterator)
|
||||
AnnotationsProvider::ConstAnnotationIterator AnnotationsProvider::GetAnnotationForEvent(EventNumberType eventIndex) const
|
||||
{
|
||||
AZ_Assert(!m_bVectorDirty, "You may not interrogate the annotations provider before it is finalized");
|
||||
|
||||
// do we have annotations for that event index?
|
||||
EventIndexToCurrentMap::const_iterator it = m_eventToIndex.find(eventIndex);
|
||||
if (it == m_eventToIndex.end())
|
||||
{
|
||||
return GetEnd();
|
||||
}
|
||||
|
||||
return m_currentAnnotations.begin() + it->second;
|
||||
}
|
||||
|
||||
// note:: claims ownership of the data in annotation.
|
||||
void AnnotationsProvider::AddAnnotation(Annotation&& target)
|
||||
{
|
||||
if (m_eventToIndex.find(target.GetEventIndex()) != m_eventToIndex.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// can we do this quickly and easily?
|
||||
if (
|
||||
(!m_bVectorDirty) && // if we're not already going to need to sort, and...
|
||||
(
|
||||
(m_currentAnnotations.empty()) || // we either have no annotations or...
|
||||
(m_currentAnnotations.back().GetEventIndex() < target.GetEventIndex()) // the fresh annotation belongs at the end anyway and we will not need to re-sort.
|
||||
)
|
||||
)
|
||||
{
|
||||
// we're adding annotations onto the end, so we will not have to sort, we can just accumulate the data.
|
||||
|
||||
m_eventToIndex[target.GetEventIndex()] = m_currentAnnotations.size();
|
||||
|
||||
// if its the first annotation for this frame, we can also add it:
|
||||
if (m_frameToIndex.find(target.GetFrameIndex()) == m_frameToIndex.end())
|
||||
{
|
||||
m_frameToIndex[target.GetFrameIndex()] = m_currentAnnotations.size();
|
||||
}
|
||||
|
||||
m_currentAnnotations.push_back(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're adding annotations out of order, we have to re-sort:
|
||||
m_currentAnnotations.push_back(target);
|
||||
m_bVectorDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// called by the main controller to sort and build the map cache.
|
||||
void AnnotationsProvider::Finalize()
|
||||
{
|
||||
/*
|
||||
// temp: add some fake annots
|
||||
AddAnnotation(Annotation(5, 10, "Test annotation", "tracker"));
|
||||
AddAnnotation(Annotation(15, 110, "Test annotation2", "tracker1"));
|
||||
AddAnnotation(Annotation(25, 210, "Test annotatio3n", "tracker2"));
|
||||
AddAnnotation(Annotation(35, 310, "Test annotation4", "tracker3"));
|
||||
*/
|
||||
|
||||
if (!m_bVectorDirty)
|
||||
{
|
||||
emit AnnotationDataInvalidated();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_frameToIndex.clear();
|
||||
m_eventToIndex.clear();
|
||||
|
||||
// sort them so they are in order from beginning to end:
|
||||
AZStd::sort(
|
||||
m_currentAnnotations.begin(),
|
||||
m_currentAnnotations.end(),
|
||||
[](const Annotation& a, const Annotation& b) -> bool
|
||||
{
|
||||
return a.GetEventIndex() < b.GetEventIndex();
|
||||
}
|
||||
);
|
||||
|
||||
// now build the lookup tables:
|
||||
FrameNumberType lastFrameIndex = -1;
|
||||
for (AZStd::size_t idx = 0, endIdx = m_currentAnnotations.size(); idx < endIdx; ++idx)
|
||||
{
|
||||
const Annotation& current = m_currentAnnotations[idx];
|
||||
m_eventToIndex[current.GetEventIndex()] = idx;
|
||||
if (lastFrameIndex != current.GetFrameIndex())
|
||||
{
|
||||
m_frameToIndex[current.GetFrameIndex()] = idx;
|
||||
lastFrameIndex = current.GetFrameIndex();
|
||||
}
|
||||
}
|
||||
|
||||
emit AnnotationDataInvalidated();
|
||||
|
||||
m_bVectorDirty = false;
|
||||
}
|
||||
|
||||
const ChannelContainer& AnnotationsProvider::GetAllKnownChannels() const
|
||||
{
|
||||
return m_ptrUserSettings->m_KnownAnnotationChannels;
|
||||
}
|
||||
|
||||
void AnnotationsProvider::GetCurrentlyEnabledChannelCRCs(ChannelCRCContainer& target) const
|
||||
{
|
||||
target.insert(m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.begin(), m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.end());
|
||||
}
|
||||
|
||||
// let us know that a channel exists:
|
||||
void AnnotationsProvider::NotifyOfChannelExistence(const char* name)
|
||||
{
|
||||
if (m_ptrUserSettings->m_KnownAnnotationChannels.insert(name).second)
|
||||
{
|
||||
emit KnownAnnotationsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsProvider::SetChannelEnabled(const char* channelName, bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
if (m_ptrWorkspaceSettings->m_ActiveAnnotationChannels.insert(channelName).second)
|
||||
{
|
||||
m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.insert(AZ::Crc32(channelName));
|
||||
NotifyOfChannelExistence(channelName);
|
||||
emit SelectedAnnotationsChanged();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::u32 channelCRC = AZ::Crc32(channelName);
|
||||
if (IsChannelEnabled(channelCRC))
|
||||
{
|
||||
m_ptrWorkspaceSettings->m_ActiveAnnotationChannels.erase(channelName);
|
||||
m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.erase(channelCRC);
|
||||
emit SelectedAnnotationsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QColor AnnotationsProvider::GetColorForChannel(AZ::u32 channelNameCRC) const
|
||||
{
|
||||
QRgb rgbaValue = m_ptrUserSettings->GetRGBAColorForChannel(channelNameCRC);
|
||||
return QColor(rgbaValue);
|
||||
}
|
||||
|
||||
void AnnotationsProvider::SetColorForChannel(AZ::u32 channelNameCRC, QColor newColor)
|
||||
{
|
||||
QRgb rgbaValue = newColor.rgba();
|
||||
m_ptrUserSettings->SetRGBAColorForChannel(channelNameCRC, rgbaValue);
|
||||
|
||||
if (IsChannelEnabled(channelNameCRC))
|
||||
{
|
||||
// update displays
|
||||
emit SelectedAnnotationsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsProvider::ResetColorForChannel(AZ::u32 channelNameCRC)
|
||||
{
|
||||
m_ptrUserSettings->ResetColorForChannel(channelNameCRC);
|
||||
}
|
||||
|
||||
bool AnnotationsProvider::IsChannelEnabled(AZ::u32 channelNameCRC) const
|
||||
{
|
||||
return (m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.find(channelNameCRC) != m_ptrWorkspaceSettings->m_ActiveAnnotationChannelCRCs.end());
|
||||
}
|
||||
|
||||
void AnnotationsProvider::Clear()
|
||||
{
|
||||
m_frameToIndex.clear();
|
||||
m_eventToIndex.clear();
|
||||
m_currentAnnotations.clear();
|
||||
m_bVectorDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_Annotations.cpp>
|
||||
@@ -1,135 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DRILLER_ANNOTATIONS_H
|
||||
#define DRILLER_ANNOTATIONS_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <QObject>
|
||||
|
||||
#include <Source/Driller/DrillerDataTypes.h>
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AZ { class ReflectContext; }
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// Annotation
|
||||
// represents one annotation returned or fed into the annotations interface.
|
||||
class Annotation
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(Annotation, AZ::SystemAllocator, 0);
|
||||
Annotation();
|
||||
Annotation(AZ::s64 eventID, FrameNumberType frame, const char* text, const char* channel);
|
||||
Annotation(const Annotation& other);
|
||||
Annotation(Annotation&& other);
|
||||
Annotation& operator=(Annotation&& other);
|
||||
Annotation& operator=(const Annotation& other);
|
||||
|
||||
AZ::s64 GetEventIndex() const { return m_eventIndex; }
|
||||
FrameNumberType GetFrameIndex() const { return m_frameIndex; }
|
||||
const AZStd::string& GetText() const { return m_text; }
|
||||
const AZStd::string& GetChannel() const { return m_channel; }
|
||||
const AZ::u32 GetChannelCRC() const { return m_ChannelCRC; }
|
||||
|
||||
private:
|
||||
AZ::s64 m_eventIndex;
|
||||
FrameNumberType m_frameIndex;
|
||||
AZStd::string m_text;
|
||||
AZStd::string m_channel;
|
||||
AZ::u32 m_ChannelCRC;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// AnnotationsProviderInterface
|
||||
// a class which provides annotation information to the parts of the system that care about annotations.
|
||||
// other parts of the system that want to know what annotations occur where will be given a pointer to this guy
|
||||
// and they will ask him what they need to know.
|
||||
// PLEASE NOTE: This is essentially a live cache of what's currently in the view range and is for rendering only.
|
||||
// its essentially destroyed and recreated every frame.
|
||||
|
||||
class AnnotationWorkspaceSettings;
|
||||
class AnnotationUserSettings;
|
||||
class WorkspaceSettingsProvider;
|
||||
|
||||
// contains a set of channel names
|
||||
typedef AZStd::unordered_set<AZStd::string> ChannelContainer;
|
||||
typedef AZStd::unordered_set<AZ::u32> ChannelCRCContainer;
|
||||
|
||||
class AnnotationsProvider
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AnnotationsProvider, AZ::SystemAllocator, 0);
|
||||
|
||||
typedef AZStd::vector<Annotation> AnnotationContainer;
|
||||
typedef AnnotationContainer::const_iterator ConstAnnotationIterator;
|
||||
|
||||
// graph renderers need to know what color to draw annotations, and what annotations exist given a particular event or frame:
|
||||
ConstAnnotationIterator GetEnd() const; // returns the end of the vector (ie, the invalid iterator)
|
||||
ConstAnnotationIterator GetFirstAnnotationForFrame(FrameNumberType frameIndex) const; // returns iterator to the first annotation thats on the frame given (or the end iterator)
|
||||
ConstAnnotationIterator GetAnnotationForEvent(EventNumberType eventIndex) const; // returns iterator to the first annotation that is for that event # (or the end iterator)
|
||||
|
||||
// claims ownership of the given annotation, via r-value ref. This is used during populate.
|
||||
void AddAnnotation(Annotation&& target);
|
||||
|
||||
// configure a channel
|
||||
void ConfigureChannel(const char* channel, QColor color);
|
||||
|
||||
AnnotationsProvider(QObject* pParent = NULL);
|
||||
~AnnotationsProvider();
|
||||
|
||||
// called by the main controller to sort and build the map cache.
|
||||
void Finalize();
|
||||
void Clear();
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// --- channel management ---
|
||||
const ChannelContainer& GetAllKnownChannels() const;
|
||||
void GetCurrentlyEnabledChannelCRCs(ChannelCRCContainer& target) const;
|
||||
void NotifyOfChannelExistence(const char* name);
|
||||
void SetChannelEnabled(const char* channelName, bool enabled);
|
||||
bool IsChannelEnabled(AZ::u32 channelNameCRC) const;
|
||||
QColor GetColorForChannel(AZ::u32 channelNameCRC) const; // each channel has a color, this is configured externally.
|
||||
void SetColorForChannel(AZ::u32 channelNameCRC, QColor newColor); // each channel has a color, this is configured externally.
|
||||
void ResetColorForChannel(AZ::u32 channelNameCRC); // each channel has a color, this is configured externally.
|
||||
|
||||
void LoadSettingsFromWorkspace(WorkspaceSettingsProvider* ptrProvider);
|
||||
void SaveSettingsToWorkspace(WorkspaceSettingsProvider* ptrProvider);
|
||||
signals:
|
||||
void KnownAnnotationsChanged();
|
||||
void SelectedAnnotationsChanged();
|
||||
void AnnotationDataInvalidated();
|
||||
|
||||
protected:
|
||||
AnnotationContainer m_currentAnnotations;
|
||||
typedef AZStd::unordered_map<EventNumberType, AZStd::size_t> EventIndexToCurrentMap; // maps from event index to index in our vector.
|
||||
typedef AZStd::unordered_map<FrameNumberType, AZStd::size_t> FrameIndexToCurrentMap; // maps from frame index to index in our vector.
|
||||
EventIndexToCurrentMap m_eventToIndex;
|
||||
FrameIndexToCurrentMap m_frameToIndex;
|
||||
|
||||
// housekeeping
|
||||
bool m_bVectorDirty;
|
||||
|
||||
AZStd::intrusive_ptr<AnnotationWorkspaceSettings> m_ptrWorkspaceSettings; // loaded from workspace and user settings. // crc(somethingelse)
|
||||
AZStd::intrusive_ptr<AnnotationUserSettings> m_ptrUserSettings; // loaded only from user settings / CRC(whatever)
|
||||
};
|
||||
}
|
||||
|
||||
#endif//DRILLER_ANNOTATIONS_H
|
||||
@@ -1,211 +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 "AnnotationsDataView.hxx"
|
||||
#include "AnnotationHeaderView.hxx"
|
||||
#include "Annotations.hxx"
|
||||
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
static const float adv_arrow_width = 8.0f;
|
||||
|
||||
AnnotationsDataView::AnnotationsDataView(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_ptrHeaderView(nullptr)
|
||||
, m_ptrAnnotations(nullptr)
|
||||
{
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
AnnotationsDataView::~AnnotationsDataView()
|
||||
{
|
||||
}
|
||||
|
||||
void AnnotationsDataView::RegisterAnnotationHeaderView(AnnotationHeaderView* header, AnnotationsProvider* annotations)
|
||||
{
|
||||
m_ptrHeaderView = header;
|
||||
m_ptrAnnotations = annotations;
|
||||
}
|
||||
|
||||
int AnnotationsDataView::PositionToFrame(const QPoint& pt)
|
||||
{
|
||||
QRect wrect = rect();
|
||||
|
||||
int frame = m_ptrHeaderView->GetState().m_FrameOffset + m_ptrHeaderView->GetState().m_FramesInView - 1;
|
||||
frame = frame <= m_ptrHeaderView->GetState().m_EndFrame ? frame : m_ptrHeaderView->GetState().m_EndFrame;
|
||||
|
||||
int rOffset = wrect.width() - pt.x();
|
||||
int rCell = (int)((float)rOffset / GetBarWidth());
|
||||
int retFrame = frame - rCell;
|
||||
|
||||
//AZ_TracePrintf("Driller","Click Frame Raw Input = %d\n", retFrame);
|
||||
|
||||
return retFrame;
|
||||
}
|
||||
|
||||
float AnnotationsDataView::GetBarWidth()
|
||||
{
|
||||
return ((float)(rect().width()) / (float)(m_ptrHeaderView->GetState().m_FramesInView));
|
||||
}
|
||||
|
||||
void AnnotationsDataView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
(void)event;
|
||||
|
||||
m_ClickableAreas.clear();
|
||||
|
||||
QPen pen;
|
||||
pen.setWidth(1);
|
||||
QBrush brush;
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
pen.setBrush(brush);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
|
||||
painter.setPen(pen);
|
||||
painter.fillRect(rect(), Qt::black);
|
||||
|
||||
int frame = m_ptrHeaderView->GetState().m_FrameOffset + m_ptrHeaderView->GetState().m_FramesInView - 1;
|
||||
frame = frame <= m_ptrHeaderView->GetState().m_EndFrame ? frame : m_ptrHeaderView->GetState().m_EndFrame;
|
||||
|
||||
QRect wrect = rect();
|
||||
|
||||
float barWidth = GetBarWidth();
|
||||
int barWidthHalf = (int)(barWidth / 2.0f);
|
||||
|
||||
QPen fatPen(QColor(255, 255, 255, 255));
|
||||
fatPen.setWidth(2);
|
||||
fatPen.setCapStyle(Qt::FlatCap);
|
||||
|
||||
if (m_ptrHeaderView->GetState().m_EndFrame)
|
||||
{
|
||||
float rightEdgeOfBar = (float)wrect.right();
|
||||
float leftEdgeOfBar = rightEdgeOfBar - barWidth;
|
||||
|
||||
while (frame >= 0 && rightEdgeOfBar >= wrect.left())
|
||||
{
|
||||
int actualLeftEdge = (int)floorf(leftEdgeOfBar);
|
||||
|
||||
float center = (float)(actualLeftEdge + barWidthHalf) + 0.5f;
|
||||
|
||||
// annotations?
|
||||
AnnotationsProvider::ConstAnnotationIterator it = m_ptrAnnotations->GetFirstAnnotationForFrame(frame);
|
||||
AnnotationsProvider::ConstAnnotationIterator endIt = m_ptrAnnotations->GetEnd();
|
||||
|
||||
while ((it != endIt) && (it->GetFrameIndex() == frame))
|
||||
{
|
||||
QPainterPath newPath;
|
||||
QPolygonF newPolygon;
|
||||
newPolygon << QPointF(center - adv_arrow_width, 1.0f) << QPointF(center, wrect.height() - 1.0f) << QPointF(center + adv_arrow_width, 1.0f);
|
||||
newPath.addPolygon(newPolygon);
|
||||
newPath.closeSubpath();
|
||||
|
||||
if (m_eventsToHighlight.find(it->GetEventIndex()) != m_eventsToHighlight.end())
|
||||
{
|
||||
painter.setPen(fatPen);
|
||||
painter.setBrush(m_ptrAnnotations->GetColorForChannel(it->GetChannelCRC()));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.setPen(QColor(0, 0, 0, 0));
|
||||
painter.setBrush(m_ptrAnnotations->GetColorForChannel(it->GetChannelCRC()));
|
||||
}
|
||||
painter.drawPath(newPath);
|
||||
m_ClickableAreas[it->GetEventIndex()] = newPath;
|
||||
++it;
|
||||
}
|
||||
|
||||
--frame;
|
||||
rightEdgeOfBar -= barWidth;
|
||||
leftEdgeOfBar -= barWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsDataView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
AZStd::unordered_set<AZ::s64> newEventsToHighlight;
|
||||
|
||||
for (auto it = m_ClickableAreas.begin(); it != m_ClickableAreas.end(); ++it)
|
||||
{
|
||||
if (it->second.contains(event->pos()))
|
||||
{
|
||||
auto annot = m_ptrAnnotations->GetAnnotationForEvent(it->first);
|
||||
if (annot != m_ptrAnnotations->GetEnd())
|
||||
{
|
||||
newEventsToHighlight.insert(annot->GetEventIndex());
|
||||
emit InformOfMouseOverAnnotation(*annot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool doUpdate = false;
|
||||
// did our highlight change?
|
||||
for (auto it = newEventsToHighlight.begin(); it != newEventsToHighlight.end(); ++it)
|
||||
{
|
||||
if (m_eventsToHighlight.find(*it) == m_eventsToHighlight.end())
|
||||
{
|
||||
doUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// did our highlight change?
|
||||
if (!doUpdate)
|
||||
{
|
||||
for (auto it = m_eventsToHighlight.begin(); it != m_eventsToHighlight.end(); ++it)
|
||||
{
|
||||
if (newEventsToHighlight.find(*it) == newEventsToHighlight.end())
|
||||
{
|
||||
doUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doUpdate)
|
||||
{
|
||||
newEventsToHighlight.swap(m_eventsToHighlight);
|
||||
update();
|
||||
}
|
||||
|
||||
// find the first annotation within a margin:
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void AnnotationsDataView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
for (auto it = m_ClickableAreas.begin(); it != m_ClickableAreas.end(); ++it)
|
||||
{
|
||||
if (it->second.contains(event->pos()))
|
||||
{
|
||||
auto annot = m_ptrAnnotations->GetAnnotationForEvent(it->first);
|
||||
if (annot != m_ptrAnnotations->GetEnd())
|
||||
{
|
||||
emit InformOfClickAnnotation(*annot);
|
||||
}
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void AnnotationsDataView::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_AnnotationsDataView.cpp>
|
||||
@@ -1,61 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANNOTATIONS_DATA_VIEW
|
||||
#define ANNOTATIONS_DATA_VIEW
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
class AnnotationsProvider;
|
||||
class Annotation;
|
||||
class AnnotationHeaderView;
|
||||
/** Annotations Data View just shows the annotations that are available in a horizontal strip with indicators for easy clickability.
|
||||
*/
|
||||
|
||||
class AnnotationsDataView : public QWidget
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AnnotationsDataView, AZ::SystemAllocator, 0);
|
||||
AnnotationsDataView(QWidget* parent = nullptr);
|
||||
virtual ~AnnotationsDataView();
|
||||
|
||||
void RegisterAnnotationHeaderView(AnnotationHeaderView* header, AnnotationsProvider* annotations);
|
||||
|
||||
int PositionToFrame( const QPoint &pt );
|
||||
|
||||
float GetBarWidth();
|
||||
|
||||
virtual void paintEvent( QPaintEvent *event );
|
||||
virtual void mouseMoveEvent( QMouseEvent *event );
|
||||
virtual void mousePressEvent( QMouseEvent *event );
|
||||
virtual void mouseReleaseEvent( QMouseEvent *event );
|
||||
|
||||
signals:
|
||||
void InformOfMouseOverAnnotation(const Annotation& annotation);
|
||||
void InformOfClickAnnotation(const Annotation& annotation);
|
||||
private:
|
||||
typedef AZStd::unordered_map<AZ::s64, QPainterPath> EventIndexToClickablePath;
|
||||
EventIndexToClickablePath m_ClickableAreas;
|
||||
AZStd::unordered_set<AZ::s64> m_eventsToHighlight;
|
||||
|
||||
AnnotationsProvider *m_ptrAnnotations;
|
||||
AnnotationHeaderView *m_ptrHeaderView;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANNOTATIONS_DATA_VIEW
|
||||
@@ -1,250 +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 "AnnotationsDataView_Events.hxx"
|
||||
#include "AnnotationsHeaderView_Events.hxx"
|
||||
#include "Annotations.hxx"
|
||||
#include <Source/Driller/Axis.hxx>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPen>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
static const float adv_events_arrow_width = 8.0f;
|
||||
|
||||
AnnotationsDataView_Events::AnnotationsDataView_Events(AnnotationHeaderView_Events* header, AnnotationsProvider* annotations)
|
||||
: QWidget(header)
|
||||
, m_ptrHeaderView(header)
|
||||
, m_ptrAnnotations(annotations)
|
||||
, m_ptrAxis(NULL)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setFixedHeight(18);
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setMouseTracking(true);
|
||||
m_CurrentFrameNumber = 0;
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::AttachToAxis(Charts::Axis* pAxis)
|
||||
{
|
||||
if (m_ptrAxis)
|
||||
{
|
||||
disconnect(m_ptrAxis, SIGNAL(destroyed(QObject*)), this, SLOT(OnAxisDestroyed()));
|
||||
disconnect(m_ptrAxis, SIGNAL(Invalidated()), this, SLOT(OnAxisInvalidated()));
|
||||
}
|
||||
|
||||
m_ptrAxis = pAxis;
|
||||
if (pAxis)
|
||||
{
|
||||
connect(m_ptrAxis, SIGNAL(destroyed(QObject*)), this, SLOT(OnAxisDestroyed()));
|
||||
connect(m_ptrAxis, SIGNAL(Invalidated()), this, SLOT(OnAxisInvalidated()));
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::OnAxisDestroyed()
|
||||
{
|
||||
m_ptrAxis = NULL;
|
||||
update();
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::OnAxisInvalidated()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
AnnotationsDataView_Events::~AnnotationsDataView_Events()
|
||||
{
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
(void)event;
|
||||
|
||||
m_ClickableAreas.clear();
|
||||
|
||||
// scan for annotations
|
||||
|
||||
|
||||
|
||||
// fill with black
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect(), Qt::black);
|
||||
|
||||
if (!m_ptrAxis)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ptrAxis->GetValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF drawRange = rect();
|
||||
// adjust for inset:
|
||||
|
||||
drawRange.adjust(2.0f, 0.0f, -4.0f, 0.0f);
|
||||
float leftEdge = (float)drawRange.left();
|
||||
float drawRangeWidth = (float)drawRange.width();
|
||||
|
||||
AZ::s64 eventIndexStart = (AZ::s64)m_ptrAxis->GetWindowMin();
|
||||
AZ::s64 eventIndexEnd = (AZ::s64)m_ptrAxis->GetWindowMax() + 1;
|
||||
float eventIndexRange = ((float)m_ptrAxis->GetWindowMax() - (float)m_ptrAxis->GetWindowMin()); // this is the domain range
|
||||
|
||||
|
||||
if (eventIndexRange <= 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float oneEventWidthInPixels = drawRangeWidth / eventIndexRange;
|
||||
float halfEventWidth = oneEventWidthInPixels * 0.5f;
|
||||
|
||||
// find the first event within that range:
|
||||
QPen fatPen(QColor(255, 255, 255, 255));
|
||||
fatPen.setWidth(2);
|
||||
fatPen.setCapStyle(Qt::FlatCap);
|
||||
|
||||
AnnotationsProvider::ConstAnnotationIterator it = m_ptrAnnotations->GetFirstAnnotationForFrame(m_CurrentFrameNumber);
|
||||
AnnotationsProvider::ConstAnnotationIterator endIt = m_ptrAnnotations->GetEnd();
|
||||
|
||||
// now keep going until we hit the end of the range:
|
||||
while (it != endIt)
|
||||
{
|
||||
if (it->GetEventIndex() >= eventIndexEnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (it->GetEventIndex() < eventIndexStart)
|
||||
{
|
||||
++it;
|
||||
continue; // we're within the zoom
|
||||
}
|
||||
|
||||
// transform that event ID into the window domain:
|
||||
|
||||
|
||||
float eventRatio = ((float)it->GetEventIndex() - m_ptrAxis->GetWindowMin()) / eventIndexRange;
|
||||
|
||||
float center = floorf(leftEdge + (drawRangeWidth * eventRatio));
|
||||
|
||||
center += (float)drawRange.left();
|
||||
center += halfEventWidth;
|
||||
|
||||
QPainterPath newPath;
|
||||
QPolygonF newPolygon;
|
||||
newPolygon << QPointF(center - adv_events_arrow_width, 1.0f) << QPointF(center, drawRange.height() - 1.0f) << QPointF(center + adv_events_arrow_width, 1.0f);
|
||||
newPath.addPolygon(newPolygon);
|
||||
newPath.closeSubpath();
|
||||
|
||||
if (m_eventsToHighlight.find(it->GetEventIndex()) != m_eventsToHighlight.end())
|
||||
{
|
||||
painter.setPen(fatPen);
|
||||
painter.setBrush(m_ptrAnnotations->GetColorForChannel(it->GetChannelCRC()));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.setPen(QColor(0, 0, 0, 0));
|
||||
painter.setBrush(m_ptrAnnotations->GetColorForChannel(it->GetChannelCRC()));
|
||||
}
|
||||
painter.drawPath(newPath);
|
||||
m_ClickableAreas[it->GetEventIndex()] = newPath;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
AZStd::unordered_set<AZ::s64> newEventsToHighlight;
|
||||
|
||||
for (auto it = m_ClickableAreas.begin(); it != m_ClickableAreas.end(); ++it)
|
||||
{
|
||||
if (it->second.contains(event->pos()))
|
||||
{
|
||||
auto annot = m_ptrAnnotations->GetAnnotationForEvent(it->first);
|
||||
if (annot != m_ptrAnnotations->GetEnd())
|
||||
{
|
||||
newEventsToHighlight.insert(annot->GetEventIndex());
|
||||
emit InformOfMouseOverAnnotation(*annot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool doUpdate = false;
|
||||
// did our highlight change?
|
||||
for (auto it = newEventsToHighlight.begin(); it != newEventsToHighlight.end(); ++it)
|
||||
{
|
||||
if (m_eventsToHighlight.find(*it) == m_eventsToHighlight.end())
|
||||
{
|
||||
doUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// did our highlight change?
|
||||
if (!doUpdate)
|
||||
{
|
||||
for (auto it = m_eventsToHighlight.begin(); it != m_eventsToHighlight.end(); ++it)
|
||||
{
|
||||
if (newEventsToHighlight.find(*it) == newEventsToHighlight.end())
|
||||
{
|
||||
doUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doUpdate)
|
||||
{
|
||||
newEventsToHighlight.swap(m_eventsToHighlight);
|
||||
update();
|
||||
}
|
||||
|
||||
// find the first annotation within a margin:
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
for (auto it = m_ClickableAreas.begin(); it != m_ClickableAreas.end(); ++it)
|
||||
{
|
||||
if (it->second.contains(event->pos()))
|
||||
{
|
||||
auto annot = m_ptrAnnotations->GetAnnotationForEvent(it->first);
|
||||
if (annot != m_ptrAnnotations->GetEnd())
|
||||
{
|
||||
emit InformOfClickAnnotation(*annot);
|
||||
}
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
|
||||
void AnnotationsDataView_Events::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void AnnotationsDataView_Events::OnScrubberFrameUpdate(FrameNumberType newFramenumber)
|
||||
{
|
||||
if (newFramenumber != m_CurrentFrameNumber)
|
||||
{
|
||||
m_CurrentFrameNumber = newFramenumber;
|
||||
// we don't update here because we wait for the new range to be set
|
||||
//update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_AnnotationsDataView_Events.cpp>
|
||||
@@ -1,77 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANNOTATIONS_DATA_VIEW_EVENTS_HXX
|
||||
#define ANNOTATIONS_DATA_VIEW_EVENTS_HXX
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include "Source/Driller/DrillerDataTypes.h"
|
||||
#endif
|
||||
|
||||
namespace Charts
|
||||
{
|
||||
class Axis;
|
||||
}
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
class AnnotationsProvider;
|
||||
class Annotation;
|
||||
class AnnotationHeaderView_Events;
|
||||
/** Annotations Data View just shows the annotations that are available in a horizontal strip with indicators for easy clickability.
|
||||
* This flavor of the view is supposed to operate on individual events instead of individual frames and is supposed to sit above the event driller track
|
||||
* But it can actually work on any track thats willing to provide it with an axis.
|
||||
*/
|
||||
|
||||
class AnnotationsDataView_Events : public QWidget
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AnnotationsDataView_Events, AZ::SystemAllocator, 0);
|
||||
AnnotationsDataView_Events( AnnotationHeaderView_Events* header, AnnotationsProvider *annotations );
|
||||
virtual ~AnnotationsDataView_Events();
|
||||
|
||||
void AttachToAxis(Charts::Axis *pAxis);
|
||||
|
||||
virtual void paintEvent( QPaintEvent *event );
|
||||
virtual void mouseMoveEvent( QMouseEvent *event );
|
||||
virtual void mousePressEvent( QMouseEvent *event );
|
||||
virtual void mouseReleaseEvent( QMouseEvent *event );
|
||||
|
||||
signals:
|
||||
void InformOfMouseOverAnnotation(const Annotation& annotation);
|
||||
void InformOfClickAnnotation(const Annotation& annotation);
|
||||
private:
|
||||
typedef AZStd::unordered_map<AZ::s64, QPainterPath> EventIndexToClickablePath;
|
||||
|
||||
EventIndexToClickablePath m_ClickableAreas;
|
||||
AZStd::unordered_set<AZ::s64> m_eventsToHighlight;
|
||||
QPainter *m_Painter;
|
||||
Charts::Axis *m_ptrAxis;
|
||||
|
||||
AnnotationsProvider *m_ptrAnnotations;
|
||||
AnnotationHeaderView_Events *m_ptrHeaderView;
|
||||
FrameNumberType m_CurrentFrameNumber;
|
||||
|
||||
const Annotation* GetNearestAnnotationToMousePoint(QPoint pos) const;
|
||||
|
||||
public slots:
|
||||
void OnAxisInvalidated();
|
||||
void OnAxisDestroyed();
|
||||
void OnScrubberFrameUpdate(FrameNumberType newFrameNumber);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANNOTATIONS_DATA_VIEW
|
||||
@@ -1,74 +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 "AnnotationsHeaderView_Events.hxx"
|
||||
#include "AnnotationsDataView_Events.hxx"
|
||||
#include "Annotations.hxx"
|
||||
#include <QtWidgets/QGridLayout>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
static const int k_eventContractedSize = 18;
|
||||
|
||||
AnnotationHeaderView_Events::AnnotationHeaderView_Events(QWidget* parent, Qt::WindowFlags flags)
|
||||
: QWidget(parent, flags)
|
||||
, m_ptrAnnotations(NULL)
|
||||
{
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
this->setFixedHeight(k_eventContractedSize);
|
||||
this->setAutoFillBackground(true);
|
||||
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout(this);
|
||||
this->setLayout(mainLayout);
|
||||
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
}
|
||||
|
||||
void AnnotationHeaderView_Events::OnScrubberFrameUpdate(FrameNumberType newFrame)
|
||||
{
|
||||
if (m_ptrDataView)
|
||||
{
|
||||
m_ptrDataView->OnScrubberFrameUpdate(newFrame);
|
||||
}
|
||||
}
|
||||
|
||||
QSize AnnotationHeaderView_Events::sizeHint() const
|
||||
{
|
||||
return QSize(0, k_eventContractedSize);
|
||||
}
|
||||
|
||||
void AnnotationHeaderView_Events::ControllerSizeChanged(QSize newSize)
|
||||
{
|
||||
(void)newSize;
|
||||
}
|
||||
|
||||
AnnotationHeaderView_Events::~AnnotationHeaderView_Events()
|
||||
{
|
||||
}
|
||||
|
||||
void AnnotationHeaderView_Events::AttachToAxis(AnnotationsProvider* ptrAnnotations, Charts::Axis* target)
|
||||
{
|
||||
m_ptrAnnotations = ptrAnnotations;
|
||||
m_ptrDataView = aznew AnnotationsDataView_Events(this, ptrAnnotations);
|
||||
|
||||
connect(m_ptrDataView, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)), this, SIGNAL(InformOfMouseOverAnnotation(const Annotation&)));
|
||||
connect(m_ptrDataView, SIGNAL(InformOfClickAnnotation(const Annotation&)), this, SIGNAL(InformOfClickAnnotation(const Annotation&)));
|
||||
connect(m_ptrAnnotations, SIGNAL(AnnotationDataInvalidated()), this, SLOT(RefreshView()));
|
||||
|
||||
layout()->addWidget(m_ptrDataView);
|
||||
m_ptrDataView->AttachToAxis(target);
|
||||
}
|
||||
|
||||
void AnnotationHeaderView_Events::RefreshView()
|
||||
{
|
||||
m_ptrDataView->update();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_AnnotationsHeaderView_Events.cpp>
|
||||
@@ -1,65 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANNOTATION_HEADER_VIEW_EVENTS_HXX
|
||||
#define ANNOTATION_HEADER_VIEW_EVENTS_HXX
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <Source/Driller/DrillerNetworkMessages.h>
|
||||
|
||||
#include "Source/Driller/DrillerDataTypes.h"
|
||||
#endif
|
||||
|
||||
namespace Charts
|
||||
{
|
||||
class Axis;
|
||||
}
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
class AnnotationsProvider;
|
||||
class AnnotationsDataView_Events;
|
||||
class Annotation;
|
||||
|
||||
/** This version of the annotations header view sits above the per-frame events widget (near the bottom of hte main view).
|
||||
* Its job is to show annotations that happen within a single frame (on an event-by-event basis!)
|
||||
* It can actually work on any track thats willing to provide it with an axis.
|
||||
*/
|
||||
|
||||
class AnnotationHeaderView_Events : public QWidget
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AnnotationHeaderView_Events,AZ::SystemAllocator,0);
|
||||
AnnotationHeaderView_Events(QWidget* parent = NULL, Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
virtual ~AnnotationHeaderView_Events(void);
|
||||
|
||||
void AttachToAxis(AnnotationsProvider* ptrAnnotations, Charts::Axis *target);
|
||||
signals:
|
||||
void InformOfMouseOverAnnotation(const Annotation& annotation);
|
||||
void InformOfClickAnnotation(const Annotation& annotation);
|
||||
|
||||
public slots:
|
||||
void RefreshView();
|
||||
void ControllerSizeChanged(QSize newSize);
|
||||
void OnScrubberFrameUpdate(FrameNumberType newFrame);
|
||||
private:
|
||||
AnnotationsProvider *m_ptrAnnotations;
|
||||
AnnotationsDataView_Events *m_ptrDataView;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ANNOTATION_HEADER_VIEW_HXX
|
||||
@@ -1,151 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>configureAnnotationsDialog</class>
|
||||
<widget class="QDialog" name="configureAnnotationsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>446</width>
|
||||
<height>168</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Configure Annotations</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Display Annotations From the Selected Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchField">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Search Annotations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="statusTable">
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||
<number>60</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderDefaultSectionSize">
|
||||
<number>30</number>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,248 +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 <QtCore/QAbstractTableModel>
|
||||
#include "ConfigureAnnotationsWindow.hxx"
|
||||
#include <Source/Driller/Annotations/ui_ConfigureAnnotationsDialog.h>
|
||||
#include <Source/Driller/Annotations/Annotations.hxx>
|
||||
#include <AzCore/UserSettings/UserSettings.h>
|
||||
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
|
||||
#include <AzToolsFramework/UI/UICore/ColorPickerDelegate.hxx>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QCloseEvent>
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
//////////////////////////////
|
||||
// ConfigureAnnotationsModel
|
||||
//////////////////////////////
|
||||
int ConfigureAnnotationsModel::rowCount(const QModelIndex& index) const
|
||||
{
|
||||
if (index == QModelIndex())
|
||||
{
|
||||
return (int)m_cache.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConfigureAnnotationsModel::columnCount(const QModelIndex& index) const
|
||||
{
|
||||
(void)index;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Qt::ItemFlags ConfigureAnnotationsModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
if (index == QModelIndex())
|
||||
{
|
||||
return Qt::ItemFlags();
|
||||
}
|
||||
|
||||
if (index.column() == 0)
|
||||
{
|
||||
return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
bool ConfigureAnnotationsModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
if (role == Qt::CheckStateRole)
|
||||
{
|
||||
Qt::CheckState newState = (Qt::CheckState)value.toInt();
|
||||
if (index.column() == 0)
|
||||
{
|
||||
if (index.row() < (int)m_cache.size())
|
||||
{
|
||||
Qt::CheckState oldEnabled = m_ptrProvider->IsChannelEnabled(AZ::Crc32(m_cache[index.row()].toUtf8().data())) ? Qt::Checked : Qt::Unchecked;
|
||||
|
||||
if (newState != oldEnabled)
|
||||
{
|
||||
m_ptrProvider->SetChannelEnabled(m_cache[index.row()].toUtf8().data(), newState == Qt::Checked ? true : false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == AzToolsFramework::ColorPickerDelegate::COLOR_PICKER_ROLE)
|
||||
{
|
||||
QColor newColor = qvariant_cast<QColor>(value);
|
||||
AZ::u32 crcOfChannel = AZ::Crc32(m_cache[index.row()].toUtf8().data());
|
||||
m_ptrProvider->SetColorForChannel(crcOfChannel, newColor);
|
||||
m_cachedColorIcons[index.row()] = CreatePixmapForColor(newColor);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant ConfigureAnnotationsModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (index == QModelIndex())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (index.column() == 0)
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
AZ::u32 crcvalue = AZ::Crc32(m_cache[index.row()].toUtf8().data());
|
||||
return QVariant(m_ptrProvider->IsChannelEnabled(crcvalue) ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked));
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
return m_cachedColorIcons[index.row()];
|
||||
}
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
return m_cache[index.row()];
|
||||
}
|
||||
case AzToolsFramework::ColorPickerDelegate::COLOR_PICKER_ROLE:
|
||||
{
|
||||
AZ::u32 crcvalue = AZ::Crc32(m_cache[index.row()].toUtf8().data());
|
||||
QColor channelColor = m_ptrProvider->GetColorForChannel(crcvalue);
|
||||
return QVariant(channelColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ConfigureAnnotationsModel::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
(void)orientation;
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case 0:
|
||||
return QVariant(tr("Annotation Type"));
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole)
|
||||
{
|
||||
if (section == 0)
|
||||
{
|
||||
return QVariant(Qt::AlignVCenter | Qt::AlignLeft);
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QPixmap ConfigureAnnotationsModel::CreatePixmapForColor(QColor color)
|
||||
{
|
||||
QPixmap pixmap(16, 16);
|
||||
{
|
||||
QPainter painter(&pixmap);
|
||||
painter.fillRect(0, 0, 16, 16, Qt::black);
|
||||
painter.fillRect(1, 1, 15, 15, color);
|
||||
}
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
|
||||
void ConfigureAnnotationsModel::Recache()
|
||||
{
|
||||
beginResetModel();
|
||||
m_cache.clear();
|
||||
m_cachedColorIcons.clear();
|
||||
AZStd::for_each(m_ptrProvider->GetAllKnownChannels().begin(), m_ptrProvider->GetAllKnownChannels().end(),
|
||||
[this](const AZStd::string& value)
|
||||
{
|
||||
m_cache.push_back(QString::fromUtf8(value.c_str()));
|
||||
QColor channelColor = m_ptrProvider->GetColorForChannel(AZ::Crc32(value.c_str()));
|
||||
|
||||
m_cachedColorIcons.push_back(CreatePixmapForColor(channelColor));
|
||||
});
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
ConfigureAnnotationsModel::ConfigureAnnotationsModel(AnnotationsProvider* ptrProvider, QObject* pParent)
|
||||
: QAbstractTableModel(pParent)
|
||||
{
|
||||
m_ptrProvider = ptrProvider;
|
||||
connect(ptrProvider, &AnnotationsProvider::KnownAnnotationsChanged, this, &ConfigureAnnotationsModel::Recache);
|
||||
Recache();
|
||||
}
|
||||
|
||||
ConfigureAnnotationsModel::~ConfigureAnnotationsModel()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// ConfigureAnnotationsWindow
|
||||
///////////////////////////////
|
||||
|
||||
ConfigureAnnotationsWindow::ConfigureAnnotationsWindow(QWidget* pParent /* = NULL */)
|
||||
: QDialog(pParent)
|
||||
, m_proxyModel(nullptr)
|
||||
{
|
||||
m_ptrLoadedUI = azcreate(Ui::configureAnnotationsDialog, ());
|
||||
m_ptrLoadedUI->setupUi(this);
|
||||
}
|
||||
|
||||
ConfigureAnnotationsWindow::~ConfigureAnnotationsWindow()
|
||||
{
|
||||
AZStd::intrusive_ptr<AzToolsFramework::QWidgetSavedState> pState = AZ::UserSettings::CreateFind<AzToolsFramework::QWidgetSavedState>(AZ_CRC("CONFIGURE ANNOTATIONS WINDOW", 0x581c6568), AZ::UserSettings::CT_GLOBAL);
|
||||
if (pState)
|
||||
{
|
||||
pState->CaptureGeometry(this);
|
||||
}
|
||||
|
||||
azdestroy(m_ptrLoadedUI);
|
||||
}
|
||||
|
||||
void ConfigureAnnotationsWindow::Initialize(AnnotationsProvider* ptrProvider)
|
||||
{
|
||||
m_ptrProvider = ptrProvider;
|
||||
m_ptrModel = aznew ConfigureAnnotationsModel(ptrProvider, this);
|
||||
|
||||
m_proxyModel = new QSortFilterProxyModel(this);
|
||||
m_proxyModel->setDynamicSortFilter(false);
|
||||
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_proxyModel->setSourceModel(m_ptrModel);
|
||||
|
||||
m_ptrLoadedUI->statusTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_ptrLoadedUI->statusTable->setModel(m_proxyModel);
|
||||
m_ptrLoadedUI->statusTable->setItemDelegate(aznew AzToolsFramework::ColorPickerDelegate(this));
|
||||
m_ptrLoadedUI->statusTable->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
|
||||
connect(m_ptrLoadedUI->searchField, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterChanged(const QString&)));
|
||||
|
||||
AZStd::intrusive_ptr<AzToolsFramework::QWidgetSavedState> windowState = AZ::UserSettings::Find<AzToolsFramework::QWidgetSavedState>(AZ_CRC("CONFIGURE ANNOTATIONS WINDOW", 0x581c6568), AZ::UserSettings::CT_GLOBAL);
|
||||
|
||||
if (windowState)
|
||||
{
|
||||
windowState->RestoreGeometry(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureAnnotationsWindow::OnFilterChanged(const QString& filter)
|
||||
{
|
||||
m_proxyModel->setFilterFixedString(filter);
|
||||
}
|
||||
|
||||
void ConfigureAnnotationsWindow::closeEvent (QCloseEvent* e)
|
||||
{
|
||||
e->accept();
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Source/Driller/Annotations/moc_ConfigureAnnotationsWindow.cpp>
|
||||
@@ -1,91 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIGURE_ANNOTATIONS_WINDOW_H
|
||||
#define CONFIGURE_ANNOTATIONS_WINDOW_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QDialog>
|
||||
#include <QAbstractTableModel>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#endif
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class configureAnnotationsDialog;
|
||||
}
|
||||
|
||||
namespace Driller
|
||||
{
|
||||
class AnnotationsProvider;
|
||||
class ConfigureAnnotationsModel;
|
||||
|
||||
class ConfigureAnnotationsWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ConfigureAnnotationsWindow, AZ::SystemAllocator, 0);
|
||||
|
||||
ConfigureAnnotationsWindow(QWidget *pParent = NULL);
|
||||
virtual ~ConfigureAnnotationsWindow();
|
||||
|
||||
void Initialize(AnnotationsProvider* ptrProvider);
|
||||
|
||||
public slots:
|
||||
void OnFilterChanged(const QString&);
|
||||
|
||||
protected:
|
||||
Ui::configureAnnotationsDialog* m_ptrLoadedUI;
|
||||
QSortFilterProxyModel* m_proxyModel;
|
||||
ConfigureAnnotationsModel* m_ptrModel;
|
||||
AnnotationsProvider* m_ptrProvider;
|
||||
virtual void closeEvent ( QCloseEvent * e );
|
||||
};
|
||||
|
||||
|
||||
class ConfigureAnnotationsModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ConfigureAnnotationsModel, AZ::SystemAllocator, 0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractTableModel
|
||||
int rowCount(const QModelIndex& index = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& index = QModelIndex()) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
QVariant headerData ( int section, Qt::Orientation orientation, int role ) const override;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ConfigureAnnotationsModel(AnnotationsProvider* ptrProvider, QObject *pParent = NULL);
|
||||
|
||||
virtual ~ConfigureAnnotationsModel();
|
||||
|
||||
private:
|
||||
AnnotationsProvider* m_ptrProvider;
|
||||
AZStd::vector<QString> m_cache;
|
||||
AZStd::vector<QPixmap> m_cachedColorIcons;
|
||||
|
||||
QPixmap CreatePixmapForColor(QColor color);
|
||||
|
||||
private slots:
|
||||
void Recache();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //CONFIGURE_ANNOTATIONS_WINDOW_H
|
||||
@@ -1,636 +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 <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
|
||||
#include <Source/Driller/Axis.hxx>
|
||||
|
||||
#include <Source/Driller/AreaChart.hxx>
|
||||
#include <Source/Driller/moc_AreaChart.cpp>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace AreaChart
|
||||
{
|
||||
///////////////
|
||||
// LineSeries
|
||||
///////////////
|
||||
|
||||
LineSeries::LineSeries(AreaChart* owner, size_t seriesId, const QString& name, const QColor& color, size_t seriesSize)
|
||||
: m_owner(owner)
|
||||
, m_seriesId(seriesId)
|
||||
, m_name(name)
|
||||
, m_color(color)
|
||||
, m_highlighted(false)
|
||||
, m_enabled(true)
|
||||
, m_hasData(false)
|
||||
{
|
||||
if (seriesSize > 0)
|
||||
{
|
||||
m_linePoints.reserve(seriesSize);
|
||||
}
|
||||
}
|
||||
|
||||
LineSeries::~LineSeries()
|
||||
{
|
||||
}
|
||||
|
||||
size_t LineSeries::GetSeriesId() const
|
||||
{
|
||||
return m_seriesId;
|
||||
}
|
||||
|
||||
void LineSeries::AddPoint(const LinePoint& linePoint)
|
||||
{
|
||||
// Handle simple case first
|
||||
if (m_linePoints.empty() || m_linePoints.back().m_position < linePoint.m_position)
|
||||
{
|
||||
m_hasData |= linePoint.m_value > 0;
|
||||
m_linePoints.push_back(linePoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Handle the case of out of order insertion
|
||||
AZ_Error("LineSeries",false,"Trying to add series point out of order. Unsupported behavior");
|
||||
}
|
||||
}
|
||||
|
||||
void LineSeries::Reset()
|
||||
{
|
||||
m_linePoints.clear();
|
||||
}
|
||||
|
||||
bool LineSeries::IsHighlighted() const
|
||||
{
|
||||
return m_highlighted;
|
||||
}
|
||||
|
||||
bool LineSeries::IsEnabled() const
|
||||
{
|
||||
return m_enabled && m_hasData;
|
||||
}
|
||||
|
||||
const QColor& LineSeries::GetColor() const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void LineSeries::ResetPainterPath()
|
||||
{
|
||||
// Kind of silly that QPainterPath doesn't have a clear.
|
||||
m_painterPath = QPainterPath();
|
||||
}
|
||||
|
||||
QPainterPath& LineSeries::GetPainterPath()
|
||||
{
|
||||
return m_painterPath;
|
||||
}
|
||||
|
||||
const QPainterPath& LineSeries::GetPainterPath() const
|
||||
{
|
||||
return m_painterPath;
|
||||
}
|
||||
|
||||
//////////////
|
||||
// AreaChart
|
||||
//////////////
|
||||
|
||||
const size_t AreaChart::k_invalidSeriesId = static_cast<size_t>(-1);
|
||||
|
||||
AreaChart::AreaChart(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_inspectionSeries(k_invalidSeriesId)
|
||||
, m_sizingDirty(true)
|
||||
, m_regenGraph(true)
|
||||
, m_axisMin(0)
|
||||
, m_horizontalAxis(nullptr)
|
||||
, m_verticalAxis(nullptr)
|
||||
, m_insetTop(16)
|
||||
, m_insetBottom(24)
|
||||
, m_insetLeft(56)
|
||||
, m_insetRight(16)
|
||||
, m_widgetBackground(32,32,32,255)
|
||||
, m_graphBackground(Qt::black)
|
||||
{
|
||||
setStyleSheet(QString("QToolTip { border: 1px solid white; padding: 1px; background: black; color: white; }"));
|
||||
|
||||
m_axisMax = m_axisMin;
|
||||
}
|
||||
|
||||
AreaChart::~AreaChart()
|
||||
{
|
||||
delete m_horizontalAxis;
|
||||
delete m_verticalAxis;
|
||||
}
|
||||
|
||||
bool AreaChart::IsMouseInspectionEnabled() const
|
||||
{
|
||||
return hasMouseTracking();
|
||||
}
|
||||
|
||||
void AreaChart::EnableMouseInspection(bool enabled)
|
||||
{
|
||||
setMouseTracking(enabled);
|
||||
}
|
||||
|
||||
void AreaChart::SetMinimumValueRange(unsigned int value)
|
||||
{
|
||||
m_axisMin = value;
|
||||
|
||||
m_axisMax = m_axisMin;
|
||||
|
||||
for (auto& sizingPair : m_maxSizing)
|
||||
{
|
||||
if (sizingPair.second > m_axisMax)
|
||||
{
|
||||
m_axisMax = sizingPair.second;
|
||||
}
|
||||
}
|
||||
|
||||
m_regenGraph = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void AreaChart::ResetChart()
|
||||
{
|
||||
m_axisMax = m_axisMin;
|
||||
m_maxSizing.clear();
|
||||
m_lineSeries.clear();
|
||||
m_markers.clear();
|
||||
|
||||
m_sizingDirty = true;
|
||||
m_regenGraph = true;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void AreaChart::ConfigureVerticalAxis(QString label, unsigned int minimumHeight)
|
||||
{
|
||||
SetMinimumValueRange(minimumHeight);
|
||||
|
||||
if (m_verticalAxis == nullptr)
|
||||
{
|
||||
m_verticalAxis = aznew Charts::Axis();
|
||||
}
|
||||
|
||||
if (m_verticalAxis)
|
||||
{
|
||||
m_verticalAxis->SetLabel(label);
|
||||
m_verticalAxis->SetAxisRange(0.0f, static_cast<float>(m_axisMax));
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::ConfigureHorizontalAxis(QString label, int minimum, int maximum)
|
||||
{
|
||||
if (m_horizontalAxis == nullptr)
|
||||
{
|
||||
m_horizontalAxis = aznew Charts::Axis();
|
||||
}
|
||||
|
||||
if (m_horizontalAxis)
|
||||
{
|
||||
m_horizontalAxis->SetLabel(label);
|
||||
m_horizontalAxis->SetAxisRange(static_cast<float>(minimum), static_cast<float>(maximum));
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::ResetSeries(AZ::u32 seriesId)
|
||||
{
|
||||
if (!IsValidSeriesId(seriesId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_lineSeries[seriesId].Reset();
|
||||
}
|
||||
|
||||
size_t AreaChart::CreateSeries(const QString& name, const QColor& color, size_t size)
|
||||
{
|
||||
size_t seriesKey = m_lineSeries.size();
|
||||
AZ_Error("AreaChart", seriesKey != k_invalidSeriesId,"Trying to use invalid key for series Id. Too many Area Series created.");
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
size = m_maxSizing.size();
|
||||
}
|
||||
|
||||
m_lineSeries.emplace_back(this, seriesKey, name, color, size);
|
||||
|
||||
return seriesKey;
|
||||
}
|
||||
|
||||
void AreaChart::AddPoint(size_t seriesId, int position, unsigned int value)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
LinePoint linePoint(position,value);
|
||||
AddPoint(seriesId,linePoint);
|
||||
}
|
||||
|
||||
void AreaChart::AddPoint(size_t seriesId, const LinePoint& linePoint)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
if (!IsValidSeriesId(seriesId))
|
||||
{
|
||||
AZ_Error("AreaChart", false, "Invalid SeriesId given.");
|
||||
return;
|
||||
}
|
||||
|
||||
LineSeries& lineSeries = m_lineSeries[seriesId];
|
||||
|
||||
lineSeries.AddPoint(linePoint);
|
||||
|
||||
auto sizingIter = m_maxSizing.find(linePoint.m_position);
|
||||
|
||||
if (sizingIter != m_maxSizing.end())
|
||||
{
|
||||
sizingIter->second += linePoint.m_value;
|
||||
|
||||
if (sizingIter->second > m_axisMax)
|
||||
{
|
||||
m_axisMax = sizingIter->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_maxSizing[linePoint.m_position] = linePoint.m_value;
|
||||
|
||||
if (linePoint.m_value > m_axisMax)
|
||||
{
|
||||
m_axisMax = linePoint.m_value;
|
||||
}
|
||||
}
|
||||
|
||||
m_regenGraph = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void AreaChart::SetSeriesHighlight(size_t seriesId, bool highlighted)
|
||||
{
|
||||
if (IsValidSeriesId(seriesId))
|
||||
{
|
||||
LineSeries& lineSeries = m_lineSeries[seriesId];
|
||||
|
||||
lineSeries.m_highlighted = highlighted;
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::SetSeriesEnabled(size_t seriesId, bool enabled)
|
||||
{
|
||||
if (IsValidSeriesId(seriesId))
|
||||
{
|
||||
LineSeries& lineSeries = m_lineSeries[seriesId];
|
||||
|
||||
lineSeries.m_enabled = enabled;
|
||||
|
||||
// Need to regen our graph data here, since we've removed one from the listing
|
||||
m_regenGraph = true;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::AddMarker(Charts::AxisType axis, int position, const QColor& color)
|
||||
{
|
||||
m_markers.emplace_back(axis, position, color);
|
||||
}
|
||||
|
||||
void AreaChart::mouseMoveEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
if (IsMouseInspectionEnabled())
|
||||
{
|
||||
QPoint mousePos = mouseEvent->pos();
|
||||
size_t hoveredArea = k_invalidSeriesId;
|
||||
|
||||
if (m_graphRect.contains(mousePos) && m_hitAreas.size() > 0)
|
||||
{
|
||||
int offset = mousePos.x() - m_graphRect.left();
|
||||
|
||||
size_t counter = static_cast<size_t>(static_cast<float>(offset) / (static_cast<float>(m_graphRect.width())/m_hitAreas.size()));
|
||||
|
||||
bool escape = false;
|
||||
|
||||
// Need to handle the areas right at the edge of the polygons
|
||||
for (int i = -1; i <= 1; ++i)
|
||||
{
|
||||
if ((counter + i) >= m_hitAreas.size())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const AZStd::vector<HitArea>& hitAreas = m_hitAreas[counter + i];
|
||||
|
||||
for (const HitArea& hitArea : hitAreas)
|
||||
{
|
||||
QPolygon polygon = hitArea.m_polygon;
|
||||
|
||||
if (hitArea.m_polygon.containsPoint(mousePos,Qt::OddEvenFill))
|
||||
{
|
||||
hoveredArea = hitArea.m_seriesId;
|
||||
escape = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (escape)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hoveredArea != m_inspectionSeries)
|
||||
{
|
||||
m_inspectionSeries = hoveredArea;
|
||||
update();
|
||||
|
||||
// Signal out which series we are inspecting
|
||||
emit InspectedSeries(m_inspectionSeries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::leaveEvent(QEvent* event)
|
||||
{
|
||||
(void)event;
|
||||
|
||||
if (m_inspectionSeries != k_invalidSeriesId)
|
||||
{
|
||||
m_inspectionSeries = k_invalidSeriesId;
|
||||
update();
|
||||
|
||||
// Signal out which series we are inspecting
|
||||
emit InspectedSeries(m_inspectionSeries);
|
||||
}
|
||||
|
||||
if (m_clicked)
|
||||
{
|
||||
m_clicked = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::mousePressEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
if (IsMouseInspectionEnabled())
|
||||
{
|
||||
m_clicked = true;
|
||||
m_mouseDownPoint = mouseEvent->pos();
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::mouseReleaseEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
if (IsMouseInspectionEnabled() && m_clicked)
|
||||
{
|
||||
QPoint upPoint = mouseEvent->pos();
|
||||
|
||||
// Want it to be roughly the same spot.
|
||||
if ((m_mouseDownPoint - upPoint).manhattanLength() < 20)
|
||||
{
|
||||
int closestValue = 0;
|
||||
if (m_horizontalAxis && m_graphRect.width() > 0)
|
||||
{
|
||||
float ratio = static_cast<float>(upPoint.x() - m_graphRect.left()) / static_cast<float>(m_graphRect.width());
|
||||
closestValue = static_cast<int>(m_horizontalAxis->GetRangeMin()) + static_cast<int>((m_horizontalAxis->GetRange() * ratio) + 0.5f);
|
||||
}
|
||||
|
||||
emit SelectedSeries(m_inspectionSeries, closestValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AreaChart::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
(void)event;
|
||||
|
||||
m_sizingDirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void AreaChart::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
(void)event;
|
||||
|
||||
if (m_sizingDirty)
|
||||
{
|
||||
m_sizingDirty = false;
|
||||
m_regenGraph = true;
|
||||
|
||||
QPoint topLeft(rect().left() + m_insetLeft, rect().top() + m_insetTop);
|
||||
QPoint bottomRight(rect().right() - m_insetRight, rect().bottom() - m_insetBottom);
|
||||
|
||||
m_graphRect = QRect(topLeft,bottomRight);
|
||||
}
|
||||
|
||||
if (m_regenGraph)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
m_regenGraph = false;
|
||||
|
||||
if (m_verticalAxis)
|
||||
{
|
||||
m_verticalAxis->SetAxisRange(0.0f, static_cast<float>(m_axisMax));
|
||||
}
|
||||
|
||||
m_hitAreas.clear();
|
||||
m_hitAreas.reserve(m_maxSizing.size());
|
||||
m_hitAreas.resize(m_maxSizing.size());
|
||||
|
||||
// Running tally of samples that we need to keep track of to manipulate our way through
|
||||
AZStd::vector<unsigned int> runningTotal(m_maxSizing.size(), 0);
|
||||
|
||||
for (LineSeries& lineSeries : m_lineSeries)
|
||||
{
|
||||
unsigned int counter = 0;
|
||||
|
||||
// Would have to special case out the single data point sample
|
||||
if (lineSeries.IsEnabled() && lineSeries.m_linePoints.size() > 1)
|
||||
{
|
||||
unsigned int currentValue = lineSeries.m_linePoints[counter].m_value;
|
||||
|
||||
unsigned int bottomLeft = runningTotal[counter];
|
||||
unsigned int topLeft = bottomLeft + currentValue;
|
||||
|
||||
runningTotal[counter] = topLeft;
|
||||
++counter;
|
||||
|
||||
lineSeries.ResetPainterPath();
|
||||
QPainterPath& painterPath = lineSeries.GetPainterPath();
|
||||
|
||||
AZ_Assert(runningTotal.size() == lineSeries.m_linePoints.size(), "Mismatched/missing sample values given to AreaChart");
|
||||
for (; counter < lineSeries.m_linePoints.size(); ++counter)
|
||||
{
|
||||
currentValue = lineSeries.m_linePoints[counter].m_value;
|
||||
|
||||
unsigned int bottomRight = runningTotal[counter];
|
||||
unsigned int topRight = bottomRight + currentValue;
|
||||
|
||||
runningTotal[counter] = topRight;
|
||||
|
||||
QPolygon polygon;
|
||||
polygon.append(ConvertToGraphPoint(counter - 1, bottomLeft));
|
||||
polygon.append(ConvertToGraphPoint(counter - 1, topLeft));
|
||||
polygon.append(ConvertToGraphPoint(counter, topRight));
|
||||
polygon.append(ConvertToGraphPoint(counter, bottomRight));
|
||||
|
||||
painterPath.addPolygon(polygon);
|
||||
|
||||
m_hitAreas[counter].emplace_back(polygon, lineSeries.GetSeriesId());
|
||||
|
||||
bottomLeft = bottomRight;
|
||||
topLeft = topRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
QPainter p(this);
|
||||
|
||||
p.fillRect(rect(),m_widgetBackground);
|
||||
p.fillRect(m_graphRect, m_graphBackground);
|
||||
|
||||
QRect widgetBounds = rect();
|
||||
|
||||
if (m_horizontalAxis)
|
||||
{
|
||||
m_horizontalAxis->PaintAxis(Charts::AxisType::Horizontal, &p, widgetBounds, m_graphRect, nullptr);
|
||||
}
|
||||
|
||||
if (m_verticalAxis)
|
||||
{
|
||||
m_verticalAxis->PaintAxis(Charts::AxisType::Vertical, &p, widgetBounds, m_graphRect, nullptr);
|
||||
}
|
||||
|
||||
p.setClipRect(m_graphRect.left(), m_graphRect.top() - 1, m_graphRect.width() + 2, m_graphRect.height() + 2);
|
||||
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
|
||||
pen.setStyle(Qt::SolidLine);
|
||||
pen.setWidth(2);
|
||||
|
||||
for (LineSeries& lineSeries : m_lineSeries)
|
||||
{
|
||||
if (!lineSeries.IsEnabled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
brush.setColor(lineSeries.GetColor());
|
||||
p.fillPath(lineSeries.GetPainterPath(), brush);
|
||||
|
||||
if (lineSeries.IsHighlighted()
|
||||
|| lineSeries.GetSeriesId() == m_inspectionSeries)
|
||||
{
|
||||
// Then highlight it
|
||||
pen.setColor(Qt::white);
|
||||
p.setPen(pen);
|
||||
|
||||
p.drawPath(lineSeries.GetPainterPath());
|
||||
}
|
||||
}
|
||||
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
|
||||
pen.setStyle(Qt::SolidLine);
|
||||
pen.setColor( m_graphBackground );
|
||||
pen.setWidth(2);
|
||||
|
||||
p.setPen(pen);
|
||||
|
||||
for (GraphMarker& marker : m_markers)
|
||||
{
|
||||
brush.setColor(marker.m_color);
|
||||
switch (marker.m_axis)
|
||||
{
|
||||
case Charts::AxisType::Horizontal:
|
||||
{
|
||||
static const int k_barWidth = 4;
|
||||
static const int k_halfWidth = k_barWidth / 2;
|
||||
|
||||
if (!AZ::IsClose(m_horizontalAxis->GetRange(),0.0f,0.01f) )
|
||||
{
|
||||
float minRange = m_horizontalAxis->GetRangeMin();
|
||||
|
||||
float ratio = (marker.m_position - minRange) / m_horizontalAxis->GetRange();
|
||||
ratio = AZStd::GetMin(1.0f, ratio);
|
||||
|
||||
QPoint startPoint;
|
||||
startPoint.setX(m_graphRect.left() + static_cast<int>(m_graphRect.width() * ratio) - k_halfWidth);
|
||||
startPoint.setY(m_graphRect.top());
|
||||
|
||||
p.fillRect(startPoint.x(), startPoint.y(), k_barWidth, m_graphRect.height(), brush);
|
||||
p.drawRect(startPoint.x(), startPoint.y() + 1, k_barWidth, m_graphRect.height() - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Charts::AxisType::Vertical:
|
||||
{
|
||||
QPoint startPoint = ConvertToGraphPoint(0, static_cast<unsigned int>(marker.m_position));
|
||||
startPoint.setX(m_graphRect.right());
|
||||
|
||||
p.fillRect(startPoint.x(), startPoint.y(), m_graphRect.width(), 2, brush);
|
||||
p.drawRect(startPoint.x(), startPoint.y(), m_graphRect.width(), 2);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
AZ_Error("Standalone Tools", false, "Unknown axis type given to marker.");
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Charts::Axis* AreaChart::GetAxis(Charts::AxisType axisType)
|
||||
{
|
||||
switch (axisType)
|
||||
{
|
||||
case Charts::AxisType::Horizontal:
|
||||
return m_horizontalAxis;
|
||||
case Charts::AxisType::Vertical:
|
||||
return m_verticalAxis;
|
||||
default:
|
||||
AZ_Error("AreaChart", false, "Unknown AxisType.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool AreaChart::IsValidSeriesId(size_t seriesId) const
|
||||
{
|
||||
return seriesId < m_lineSeries.size();
|
||||
}
|
||||
|
||||
QPoint AreaChart::ConvertToGraphPoint(int index, unsigned int value)
|
||||
{
|
||||
QPoint graphPoint(m_graphRect.bottomLeft());
|
||||
|
||||
int maxSizes = static_cast<int>(m_maxSizing.size());
|
||||
|
||||
if (m_horizontalAxis)
|
||||
{
|
||||
maxSizes = AZStd::GetMax(maxSizes, static_cast<int>(m_horizontalAxis->GetRange()));
|
||||
}
|
||||
|
||||
if (maxSizes >= 2)
|
||||
{
|
||||
// -1, since the index is 0 based.
|
||||
graphPoint.setX(m_graphRect.left() + static_cast<int>(m_graphRect.width() * (static_cast<float>(index) / static_cast<float>(maxSizes - 1))));
|
||||
}
|
||||
|
||||
if (m_axisMax > 0)
|
||||
{
|
||||
graphPoint.setY(m_graphRect.bottom() - static_cast<int>(m_graphRect.height() * (static_cast<float>(value) / static_cast<float>(m_axisMax))));
|
||||
}
|
||||
|
||||
return graphPoint;
|
||||
}
|
||||
}
|
||||
@@ -1,212 +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
|
||||
#ifndef PROFILER_AREACHART_H
|
||||
#define PROFILER_AREACHART_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <QWidget>
|
||||
#include <QPainterPath>
|
||||
|
||||
#include <Source/Driller/ChartTypes.hxx>
|
||||
#endif
|
||||
|
||||
namespace Charts
|
||||
{
|
||||
class Axis;
|
||||
}
|
||||
|
||||
namespace AreaChart
|
||||
{
|
||||
class AreaChart;
|
||||
|
||||
struct LinePoint
|
||||
{
|
||||
public:
|
||||
LinePoint(int position, unsigned int value)
|
||||
: m_position(position)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
int m_position;
|
||||
unsigned int m_value;
|
||||
};
|
||||
|
||||
class LineSeries
|
||||
{
|
||||
private:
|
||||
friend class AreaChart;
|
||||
|
||||
typedef AZStd::vector< LinePoint > LinePoints;
|
||||
|
||||
public:
|
||||
LineSeries(AreaChart* owner, size_t seriesId, const QString& name, const QColor& color, size_t seriesSize = 0);
|
||||
~LineSeries();
|
||||
|
||||
size_t GetSeriesId() const;
|
||||
void AddPoint(const LinePoint& linePoint);
|
||||
void Reset();
|
||||
|
||||
bool IsHighlighted() const;
|
||||
bool IsEnabled() const;
|
||||
|
||||
const QColor& GetColor() const;
|
||||
|
||||
void ResetPainterPath();
|
||||
|
||||
QPainterPath& GetPainterPath();
|
||||
const QPainterPath& GetPainterPath() const;
|
||||
|
||||
private:
|
||||
|
||||
AreaChart* m_owner;
|
||||
LinePoints m_linePoints;
|
||||
|
||||
size_t m_seriesId;
|
||||
QString m_name;
|
||||
QColor m_color;
|
||||
|
||||
QPainterPath m_painterPath;
|
||||
bool m_highlighted;
|
||||
bool m_enabled;
|
||||
bool m_hasData;
|
||||
};
|
||||
|
||||
class AreaChart
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int insetTop MEMBER m_insetTop)
|
||||
Q_PROPERTY(int insetBottom MEMBER m_insetBottom)
|
||||
Q_PROPERTY(int insetLeft MEMBER m_insetLeft)
|
||||
Q_PROPERTY(int insetRight MEMBER m_insetRight)
|
||||
Q_PROPERTY(QColor widgetBackground MEMBER m_widgetBackground)
|
||||
Q_PROPERTY(QColor graphBackground MEMBER m_graphBackground)
|
||||
|
||||
struct HitArea
|
||||
{
|
||||
HitArea(const QPolygon& polygon, size_t seriesId)
|
||||
: m_polygon(polygon)
|
||||
, m_seriesId(seriesId)
|
||||
{
|
||||
}
|
||||
|
||||
QPolygon m_polygon;
|
||||
size_t m_seriesId;
|
||||
};
|
||||
|
||||
struct GraphMarker
|
||||
{
|
||||
GraphMarker(Charts::AxisType axis, int position, const QColor& color)
|
||||
: m_axis(axis)
|
||||
, m_position(position)
|
||||
, m_color(color)
|
||||
{
|
||||
}
|
||||
|
||||
Charts::AxisType m_axis;
|
||||
int m_position;
|
||||
QColor m_color;
|
||||
};
|
||||
|
||||
public:
|
||||
static const size_t k_invalidSeriesId;
|
||||
|
||||
AreaChart(QWidget* parent = nullptr);
|
||||
~AreaChart();
|
||||
|
||||
bool IsMouseInspectionEnabled() const;
|
||||
void EnableMouseInspection(bool enabled);
|
||||
|
||||
void ResetChart();
|
||||
|
||||
void ConfigureVerticalAxis(QString label, unsigned int minimumHeight = -1);
|
||||
void ConfigureHorizontalAxis(QString label, int minimum, int maximum);
|
||||
|
||||
size_t CreateSeries(const QString& name, const QColor& color, size_t size = 0);
|
||||
void ResetSeries(AZ::u32);
|
||||
|
||||
// Methods of adding points
|
||||
void AddPoint(size_t seriesId, int position, unsigned int value);
|
||||
void AddPoint(size_t seriesId, const LinePoint& linePoint);
|
||||
|
||||
// Methods of manipulating series
|
||||
void SetSeriesHighlight(size_t seriesId, bool highlighted);
|
||||
void SetSeriesEnabled(size_t seriesId, bool enabled);
|
||||
|
||||
// Methods of adding markers
|
||||
void AddMarker(Charts::AxisType axis, int position, const QColor& color);
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
void InspectedSeries(size_t seriesId);
|
||||
void SelectedSeries(size_t seriesId, int position);
|
||||
|
||||
protected:
|
||||
|
||||
// Mouse Inspection
|
||||
void mouseMoveEvent(QMouseEvent* mouseEvent) override;
|
||||
void leaveEvent(QEvent* mouseEvent) override;
|
||||
|
||||
// Mouse clicks
|
||||
void mousePressEvent(QMouseEvent* mouseEvent) override;
|
||||
void mouseReleaseEvent(QMouseEvent* mouseEvent) override;
|
||||
|
||||
void resizeEvent(QResizeEvent* resizeEvent) override;
|
||||
void paintEvent(QPaintEvent* paintEvent) override;
|
||||
|
||||
private:
|
||||
|
||||
void SetMinimumValueRange(unsigned int value);
|
||||
Charts::Axis* GetAxis(Charts::AxisType axisType);
|
||||
|
||||
bool IsValidSeriesId(size_t seriesId) const;
|
||||
|
||||
QPoint ConvertToGraphPoint(int index, unsigned int value);
|
||||
|
||||
AZStd::vector< GraphMarker > m_markers;
|
||||
AZStd::vector< LineSeries > m_lineSeries;
|
||||
|
||||
AZStd::unordered_map<int, unsigned int> m_maxSizing;
|
||||
|
||||
size_t m_inspectionSeries;
|
||||
|
||||
size_t m_mouseOverArea;
|
||||
AZStd::vector< AZStd::vector<HitArea> > m_hitAreas;
|
||||
|
||||
bool m_clicked;
|
||||
QPoint m_mouseDownPoint;
|
||||
|
||||
QRect m_graphRect;
|
||||
bool m_sizingDirty;
|
||||
bool m_regenGraph;
|
||||
|
||||
unsigned int m_axisMin;
|
||||
unsigned int m_axisMax;
|
||||
|
||||
Charts::Axis* m_horizontalAxis;
|
||||
Charts::Axis* m_verticalAxis;
|
||||
|
||||
// Styling
|
||||
int m_insetTop;
|
||||
int m_insetBottom;
|
||||
int m_insetLeft;
|
||||
int m_insetRight;
|
||||
QColor m_widgetBackground;
|
||||
QColor m_graphBackground;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user