Files
UnrealEngine/Engine/Source/Developer/Profiler/Private/ProfilerCommands.cpp
2025-05-18 13:04:45 +08:00

362 lines
15 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ProfilerCommands.h"
#if STATS
#include "Misc/Paths.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Styling/AppStyle.h"
#include "Stats/StatsData.h"
#include "ProfilerSession.h"
#include "Widgets/SMultiDumpBrowser.h"
#include "Widgets/SProfilerWindow.h"
#include "DesktopPlatformModule.h"
#include "HAL/FileManagerGeneric.h"
#define LOCTEXT_NAMESPACE "FProfilerCommands"
/*-----------------------------------------------------------------------------
FProfilerCommands
-----------------------------------------------------------------------------*/
FProfilerCommands::FProfilerCommands()
: TCommands<FProfilerCommands>(
TEXT( "ProfilerCommand" ), // Context name for fast lookup
NSLOCTEXT("Contexts", "ProfilerCommand", "Profiler Command"), // Localized context name for displaying
NAME_None, // Parent
FAppStyle::GetAppStyleSetName() // Icon Style Set
)
{ }
/** UI_COMMAND takes long for the compile to optimize */
UE_DISABLE_OPTIMIZATION_SHIP
void FProfilerCommands::RegisterCommands()
{
/*-----------------------------------------------------------------------------
Global and custom commands.
-----------------------------------------------------------------------------*/
UI_COMMAND( ToggleDataPreview, "Data Preview", "Toggles the data preview", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control, EKeys::R ) );
UI_COMMAND( ToggleDataCapture, "Data Capture", "Toggles the data capture", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control, EKeys::C ) );
UI_COMMAND( ToggleShowDataGraph, "Show Data Graph", "Toggles showing all data graphs", EUserInterfaceActionType::ToggleButton, FInputChord() );
UI_COMMAND( OpenEventGraph, "Open Event Graph", "Opens a new event graph", EUserInterfaceActionType::Button, FInputChord() );
/*-----------------------------------------------------------------------------
Global commands.
-----------------------------------------------------------------------------*/
UI_COMMAND( ProfilerManager_Save, "Save", "Saves all collected data to file or files", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::S ) );
UI_COMMAND( StatsProfiler, "Statistics", "Enables the Stats Profiler", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control, EKeys::P ) );
#if PLATFORM_MAC
UI_COMMAND( MemoryProfiler, "Memory", "Enables the Memory Profiler", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Command, EKeys::M ) );
UI_COMMAND( FPSChart, "FPS Chart", "Shows the FPS Chart", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Command, EKeys::H ) );
#else
UI_COMMAND( MemoryProfiler, "Memory", "Enables the Memory Profiler", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control, EKeys::M ) );
UI_COMMAND( FPSChart, "FPS Chart", "Shows the FPS Chart", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control, EKeys::H ) );
#endif
UI_COMMAND( OpenSettings, "Settings", "Opens the settings for the profiler", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::O ) );
UI_COMMAND( ProfilerManager_Load, "Load", "Loads profiler data", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::L ) );
UI_COMMAND(ProfilerManager_LoadMultiple, "Load Folder", "Loads multiple stats dumps", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::L));
UI_COMMAND(ProfilerManager_ToggleLivePreview, "Live preview", "Toggles the real time live preview", EUserInterfaceActionType::ToggleButton, FInputChord());
UI_COMMAND( DataGraph_ToggleViewMode, "Toggle graph view mode", "Toggles the data graph view mode between time based and index based", EUserInterfaceActionType::Button, FInputChord() );
UI_COMMAND( DataGraph_ViewMode_SetTimeBased, "Time based", "Sets the data graph view mode to the time based", EUserInterfaceActionType::RadioButton, FInputChord() );
UI_COMMAND( DataGraph_ViewMode_SetIndexBased, "Index based", "Sets the data graph view mode to the index based", EUserInterfaceActionType::RadioButton, FInputChord() );
UI_COMMAND( EventGraph_SelectAllFrames, "Select all frames", "Selects all frames in the data graph and displays them in the event graph", EUserInterfaceActionType::Button, FInputChord() );
}
UE_ENABLE_OPTIMIZATION_SHIP
//static_assert(sizeof(FProfilerActionManager) == 0, "Cannot contain any variables at this moment.");
/*-----------------------------------------------------------------------------
FProfilerMenuBuilder
-----------------------------------------------------------------------------*/
void FProfilerMenuBuilder::AddMenuEntry( FMenuBuilder& MenuBuilder, const TSharedPtr< FUICommandInfo >& UICommandInfo, const FUIAction& UIAction )
{
MenuBuilder.AddMenuEntry
(
UICommandInfo->GetLabel(),
UICommandInfo->GetDescription(),
UICommandInfo->GetIcon(),
UIAction,
NAME_None,
UICommandInfo->GetUserInterfaceType()
);
}
/*-----------------------------------------------------------------------------
ToggleDataPreview
-----------------------------------------------------------------------------*/
void FProfilerActionManager::Map_ToggleDataPreview_Global()
{
This->CommandList->MapAction( This->GetCommands().ToggleDataPreview, ToggleDataPreview_Custom( FGuid() ) );
}
const FUIAction FProfilerActionManager::ToggleDataPreview_Custom( const FGuid SessionInstanceID ) const
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw( const_cast<FProfilerActionManager*>(this), &FProfilerActionManager::ToggleDataPreview_Execute, SessionInstanceID );
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw( this, &FProfilerActionManager::ToggleDataPreview_CanExecute, SessionInstanceID );
UIAction.GetActionCheckState = FGetActionCheckState::CreateRaw( this, &FProfilerActionManager::ToggleDataPreview_GetCheckState, SessionInstanceID );
return UIAction;
}
void FProfilerActionManager::ToggleDataPreview_Execute( const FGuid SessionInstanceID )
{
const bool bDataPreviewing = !This->IsDataPreviewing();
This->SetDataPreview( bDataPreviewing );
if (!bDataPreviewing)
{
This->bLivePreview = false;
}
}
bool FProfilerActionManager::ToggleDataPreview_CanExecute( const FGuid SessionInstanceID ) const
{
const bool bCanExecute = This->ActiveSession.IsValid() && This->ProfilerType == EProfilerSessionTypes::Live && This->ActiveInstanceID.IsValid();
return bCanExecute;
}
ECheckBoxState FProfilerActionManager::ToggleDataPreview_GetCheckState( const FGuid SessionInstanceID ) const
{
const bool bDataPreview = This->IsDataPreviewing();
return bDataPreview ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}
/*-----------------------------------------------------------------------------
ProfilerManager_ToggleLivePreview
-----------------------------------------------------------------------------*/
void FProfilerActionManager::Map_ProfilerManager_ToggleLivePreview_Global()
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw( this, &FProfilerActionManager::ProfilerManager_ToggleLivePreview_Execute );
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw( this, &FProfilerActionManager::ProfilerManager_ToggleLivePreview_CanExecute );
UIAction.GetActionCheckState = FGetActionCheckState::CreateRaw( this, &FProfilerActionManager::ProfilerManager_ToggleLivePreview_GetCheckState );
This->CommandList->MapAction( This->GetCommands().ProfilerManager_ToggleLivePreview, UIAction );
}
void FProfilerActionManager::ProfilerManager_ToggleLivePreview_Execute()
{
This->bLivePreview = !This->bLivePreview;
}
bool FProfilerActionManager::ProfilerManager_ToggleLivePreview_CanExecute() const
{
const bool bCanExecute = This->ActiveSession.IsValid() && This->ProfilerType == EProfilerSessionTypes::Live && This->ActiveInstanceID.IsValid();
return bCanExecute;
}
ECheckBoxState FProfilerActionManager::ProfilerManager_ToggleLivePreview_GetCheckState() const
{
return This->bLivePreview ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}
/*-----------------------------------------------------------------------------
ProfilerManager_Load
-----------------------------------------------------------------------------*/
void FProfilerActionManager::Map_ProfilerManager_Load()
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw( this, &FProfilerActionManager::ProfilerManager_Load_Execute );
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw( this, &FProfilerActionManager::ProfilerManager_Load_CanExecute );
This->CommandList->MapAction( This->GetCommands().ProfilerManager_Load, UIAction );
}
void FProfilerActionManager::Map_ProfilerManager_LoadMultiple()
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw(this, &FProfilerActionManager::ProfilerManager_LoadMultiple_Execute);
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw(this, &FProfilerActionManager::ProfilerManager_Load_CanExecute);
This->CommandList->MapAction(This->GetCommands().ProfilerManager_LoadMultiple, UIAction);
}
void FProfilerActionManager::ProfilerManager_Load_Execute()
{
// @see FStatConstants::StatsFileExtension
TArray<FString> OutFiles;
const FString ProfilingDirectory = *FPaths::ConvertRelativePathToFull( *FPaths::ProfilingDir() );
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
bool bOpened = false;
if( DesktopPlatform != NULL )
{
bOpened = DesktopPlatform->OpenFileDialog
(
NULL,
LOCTEXT("ProfilerManager_LoadFile_Desc", "Open profiler capture file...").ToString(),
ProfilingDirectory,
TEXT(""),
LOCTEXT("ProfilerManager_Load_FileFilter", "Stats files (*.uestats)|*.uestats|Raw Stats files (*.uestatsraw)|*.uestatsraw").ToString(),
EFileDialogFlags::None,
OutFiles
);
}
if( bOpened == true )
{
if( OutFiles.Num() == 1 )
{
const FString DraggedFileExtension = FPaths::GetExtension( OutFiles[0], true );
if( DraggedFileExtension == FStatConstants::StatsFileExtension )
{
This->LoadProfilerCapture( OutFiles[0] );
}
else if( DraggedFileExtension == FStatConstants::StatsFileRawExtension )
{
This->LoadRawStatsFile( OutFiles[0] );
}
}
}
}
void FProfilerActionManager::ProfilerManager_LoadMultiple_Execute()
{
// @see FStatConstants::StatsFileExtension
FString OutFolder;
const FString ProfilingDirectory = *FPaths::ConvertRelativePathToFull(*FPaths::ProfilingDir());
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
bool bOpened = false;
if (DesktopPlatform != NULL)
{
bOpened = DesktopPlatform->OpenDirectoryDialog(NULL,
LOCTEXT("ProfilerManager_Load_Desc", "Open capture folder...").ToString(),
ProfilingDirectory,
OutFolder);
}
if (bOpened == true)
{
This->ProfilerWindow.Pin()->MultiDumpBrowser->Clear();
if (!OutFolder.IsEmpty())
{
TArray<FString> FoundFiles;
FFileManagerGeneric::Get().FindFiles(FoundFiles, *OutFolder, TEXT(".uestats"));
for (FString &FilePath : FoundFiles)
{
const TCHAR* PathDelimiter = FPlatformMisc::GetDefaultPathSeparator();
SMultiDumpBrowser::FFileDescriptor *Desc = new SMultiDumpBrowser::FFileDescriptor();
Desc->FullPath = OutFolder + PathDelimiter + FilePath;
Desc->DisplayName = FilePath;
This->ProfilerWindow.Pin()->MultiDumpBrowser->AddFile(Desc);
}
This->ProfilerWindow.Pin()->MultiDumpBrowser->Update();
}
}
}
bool FProfilerActionManager::ProfilerManager_Load_CanExecute() const
{
const bool bIsConnectionActive = This->IsDataCapturing() || This->IsDataPreviewing() || This->IsLivePreview();
return !(bIsConnectionActive && This->ProfilerType == EProfilerSessionTypes::Live);
}
/*-----------------------------------------------------------------------------
ToggleDataCapture
-----------------------------------------------------------------------------*/
void FProfilerActionManager::Map_ToggleDataCapture_Global()
{
This->CommandList->MapAction( This->GetCommands().ToggleDataCapture, ToggleDataCapture_Custom( FGuid() ) );
}
const FUIAction FProfilerActionManager::ToggleDataCapture_Custom( const FGuid SessionInstanceID ) const
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw( const_cast<FProfilerActionManager*>(this), &FProfilerActionManager::ToggleDataCapture_Execute, SessionInstanceID );
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw( this, &FProfilerActionManager::ToggleDataCapture_CanExecute, SessionInstanceID );
UIAction.GetActionCheckState = FGetActionCheckState::CreateRaw( this, &FProfilerActionManager::ToggleDataCapture_GetCheckState, SessionInstanceID );
return UIAction;
}
void FProfilerActionManager::ToggleDataCapture_Execute( const FGuid SessionInstanceID )
{
const bool bDataCapturing = This->IsDataCapturing();
This->SetDataCapture( !bDataCapturing );
// Assumes that when data capturing is off, we have captured stats files on the service side.
const bool bNewDataCapturing = This->IsDataCapturing();
if (!bNewDataCapturing)
{
EAppReturnType::Type Result = FPlatformMisc::MessageBoxExt
(
EAppMsgType::YesNo,
*LOCTEXT("TransferServiceSideCaptureQuestion", "Would you like to transfer the captured stats file(s) to this machine? This may take some time.").ToString(),
*LOCTEXT("Question", "Question").ToString()
);
if( Result == EAppReturnType::Yes )
{
This->ProfilerClient->RequestLastCapturedFile();
}
}
}
bool FProfilerActionManager::ToggleDataCapture_CanExecute( const FGuid SessionInstanceID ) const
{
const bool bCanExecute = This->ActiveSession.IsValid() && This->ProfilerType == EProfilerSessionTypes::Live && This->ActiveInstanceID.IsValid();
return bCanExecute;
}
ECheckBoxState FProfilerActionManager::ToggleDataCapture_GetCheckState( const FGuid SessionInstanceID ) const
{
const bool bDataCapturing = This->IsDataCapturing();
return bDataCapturing ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}
/*-----------------------------------------------------------------------------
OpenSettings
-----------------------------------------------------------------------------*/
void FProfilerActionManager::Map_OpenSettings_Global()
{
This->CommandList->MapAction( This->GetCommands().OpenSettings, OpenSettings_Custom() );
}
const FUIAction FProfilerActionManager::OpenSettings_Custom() const
{
FUIAction UIAction;
UIAction.ExecuteAction = FExecuteAction::CreateRaw( const_cast<FProfilerActionManager*>(this), &FProfilerActionManager::OpenSettings_Execute );
UIAction.CanExecuteAction = FCanExecuteAction::CreateRaw( this, &FProfilerActionManager::OpenSettings_CanExecute );
return UIAction;
}
void FProfilerActionManager::OpenSettings_Execute()
{
This->GetProfilerWindow()->OpenProfilerSettings();
}
bool FProfilerActionManager::OpenSettings_CanExecute() const
{
return !This->Settings.IsEditing();
}
#undef LOCTEXT_NAMESPACE
#endif // STATS