// Copyright Epic Games, Inc. All Rights Reserved. #include "LoadingProfilerManager.h" #include "Modules/ModuleManager.h" #include "TraceServices/AnalysisService.h" #include "TraceServices/Model/LoadTimeProfiler.h" #include "WorkspaceMenuStructure.h" #include "WorkspaceMenuStructureModule.h" // Insights #include "Insights/Common/InsightsMenuBuilder.h" #include "Insights/InsightsManager.h" #include "Insights/InsightsStyle.h" #include "Insights/LoadingProfiler/Widgets/SLoadingProfilerWindow.h" #include "Insights/Table/Widgets/STableTreeView.h" #include "Insights/Widgets/STimingView.h" //////////////////////////////////////////////////////////////////////////////////////////////////// #define LOCTEXT_NAMESPACE "LoadingProfilerManager" DEFINE_LOG_CATEGORY(LoadingProfiler); TSharedPtr FLoadingProfilerManager::Instance = nullptr; //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedPtr FLoadingProfilerManager::Get() { return FLoadingProfilerManager::Instance; } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedPtr FLoadingProfilerManager::CreateInstance() { ensure(!FLoadingProfilerManager::Instance.IsValid()); if (FLoadingProfilerManager::Instance.IsValid()) { FLoadingProfilerManager::Instance.Reset(); } FLoadingProfilerManager::Instance = MakeShared(FInsightsManager::Get()->GetCommandList()); return FLoadingProfilerManager::Instance; } //////////////////////////////////////////////////////////////////////////////////////////////////// FLoadingProfilerManager::FLoadingProfilerManager(TSharedRef InCommandList) : bIsInitialized(false), bIsAvailable(false), CommandList(InCommandList), ActionManager(this), ProfilerWindow(nullptr), bIsTimingViewVisible(false), bIsEventAggregationTreeViewVisible(false), bIsObjectTypeAggregationTreeViewVisible(false), bIsPackageDetailsTreeViewVisible(false), bIsExportDetailsTreeViewVisible(false), bIsRequestsTreeViewVisible(false) { } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::Initialize(IUnrealInsightsModule& InsightsModule) { ensure(!bIsInitialized); if (bIsInitialized) { return; } bIsInitialized = true; UE_LOG(LoadingProfiler, Log, TEXT("Initialize")); // Register tick functions. OnTick = FTickerDelegate::CreateSP(this, &FLoadingProfilerManager::Tick); OnTickHandle = FTicker::GetCoreTicker().AddTicker(OnTick, 0.0f); FLoadingProfilerCommands::Register(); BindCommands(); FInsightsManager::Get()->GetSessionChangedEvent().AddSP(this, &FLoadingProfilerManager::OnSessionChanged); OnSessionChanged(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::Shutdown() { if (!bIsInitialized) { return; } bIsInitialized = false; FInsightsManager::Get()->GetSessionChangedEvent().RemoveAll(this); FLoadingProfilerCommands::Unregister(); // Unregister tick function. FTicker::GetCoreTicker().RemoveTicker(OnTickHandle); FLoadingProfilerManager::Instance.Reset(); UE_LOG(LoadingProfiler, Log, TEXT("Shutdown")); } //////////////////////////////////////////////////////////////////////////////////////////////////// FLoadingProfilerManager::~FLoadingProfilerManager() { ensure(!bIsInitialized); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::BindCommands() { ActionManager.Map_ToggleTimingViewVisibility_Global(); ActionManager.Map_ToggleEventAggregationTreeViewVisibility_Global(); ActionManager.Map_ToggleObjectTypeAggregationTreeViewVisibility_Global(); ActionManager.Map_TogglePackageDetailsTreeViewVisibility_Global(); ActionManager.Map_ToggleExportDetailsTreeViewVisibility_Global(); ActionManager.Map_ToggleRequestsTreeViewVisibility_Global(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::RegisterMajorTabs(IUnrealInsightsModule& InsightsModule) { const FInsightsMajorTabConfig& Config = InsightsModule.FindMajorTabConfig(FInsightsManagerTabs::LoadingProfilerTabId); if (Config.bIsAvailable) { // Register tab spawner for the Asset Loading Insights. FTabSpawnerEntry& TabSpawnerEntry = FGlobalTabmanager::Get()->RegisterNomadTabSpawner(FInsightsManagerTabs::LoadingProfilerTabId, FOnSpawnTab::CreateRaw(this, &FLoadingProfilerManager::SpawnTab), FCanSpawnTab::CreateRaw(this, &FLoadingProfilerManager::CanSpawnTab)) .SetDisplayName(Config.TabLabel.IsSet() ? Config.TabLabel.GetValue() : LOCTEXT("LoadingProfilerTabTitle", "Asset Loading Insights")) .SetTooltipText(Config.TabTooltip.IsSet() ? Config.TabTooltip.GetValue() : LOCTEXT("LoadingProfilerTooltipText", "Open the Asset Loading Insights tab.")) .SetIcon(Config.TabIcon.IsSet() ? Config.TabIcon.GetValue() : FSlateIcon(FInsightsStyle::GetStyleSetName(), "LoadingProfiler.Icon.Small")); TSharedRef Group = Config.WorkspaceGroup.IsValid() ? Config.WorkspaceGroup.ToSharedRef() : FInsightsManager::Get()->GetInsightsMenuBuilder()->GetInsightsToolsGroup(); TabSpawnerEntry.SetGroup(Group); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::UnregisterMajorTabs() { FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(FInsightsManagerTabs::LoadingProfilerTabId); } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef FLoadingProfilerManager::SpawnTab(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .TabRole(ETabRole::NomadTab); // Register OnTabClosed to handle I/O profiler manager shutdown. DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &FLoadingProfilerManager::OnTabClosed)); // Create the SLoadingProfilerWindow widget. TSharedRef Window = SNew(SLoadingProfilerWindow, DockTab, Args.GetOwnerWindow()); DockTab->SetContent(Window); AssignProfilerWindow(Window); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool FLoadingProfilerManager::CanSpawnTab(const FSpawnTabArgs& Args) const { return bIsAvailable; } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::OnTabClosed(TSharedRef TabBeingClosed) { RemoveProfilerWindow(); // Disable TabClosed delegate. TabBeingClosed->SetOnTabClosed(SDockTab::FOnTabClosedCallback()); } //////////////////////////////////////////////////////////////////////////////////////////////////// const TSharedRef FLoadingProfilerManager::GetCommandList() const { return CommandList; } //////////////////////////////////////////////////////////////////////////////////////////////////// const FLoadingProfilerCommands& FLoadingProfilerManager::GetCommands() { return FLoadingProfilerCommands::Get(); } //////////////////////////////////////////////////////////////////////////////////////////////////// FLoadingProfilerActionManager& FLoadingProfilerManager::GetActionManager() { return FLoadingProfilerManager::Instance->ActionManager; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool FLoadingProfilerManager::Tick(float DeltaTime) { // Check if session has Load Time events (to spawn the tab), but not too often. if (!bIsAvailable && AvailabilityCheck.Tick()) { bool bIsProviderAvailable = false; TSharedPtr Session = FInsightsManager::Get()->GetSession(); if (Session.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); if (Session->IsAnalysisComplete()) { // Never check again during this session. AvailabilityCheck.Disable(); } const Trace::ILoadTimeProfilerProvider* LoadTimeProfilerProvider = Trace::ReadLoadTimeProfilerProvider(*Session.Get()); if (LoadTimeProfilerProvider) { bIsProviderAvailable = (LoadTimeProfilerProvider->GetTimelineCount() > 0); } } else { // Do not check again until the next session changed event (see OnSessionChanged). AvailabilityCheck.Disable(); } if (bIsProviderAvailable) { bIsAvailable = true; const FName& TabId = FInsightsManagerTabs::LoadingProfilerTabId; if (FGlobalTabmanager::Get()->HasTabSpawner(TabId)) { UE_LOG(LoadingProfiler, Log, TEXT("Opening the \"Asset Loading Insights\" tab...")); FGlobalTabmanager::Get()->TryInvokeTab(TabId); } } } return true; } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::OnSessionChanged() { UE_LOG(LoadingProfiler, Log, TEXT("OnSessionChanged")); bIsAvailable = false; if (FInsightsManager::Get()->GetSession().IsValid()) { AvailabilityCheck.Enable(0.3); } else { AvailabilityCheck.Disable(); } TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->Reset(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHideTimingView(const bool bIsVisible) { bIsTimingViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::TimingViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHideEventAggregationTreeView(const bool bIsVisible) { bIsEventAggregationTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::EventAggregationTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHideObjectTypeAggregationTreeView(const bool bIsVisible) { bIsObjectTypeAggregationTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::ObjectTypeAggregationTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHidePackageDetailsTreeView(const bool bIsVisible) { bIsPackageDetailsTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::PackageDetailsTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHideExportDetailsTreeView(const bool bIsVisible) { bIsExportDetailsTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::ExportDetailsTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FLoadingProfilerManager::ShowHideRequestsTreeView(const bool bIsVisible) { bIsRequestsTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FLoadingProfilerTabs::RequestsTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE