UE4源码阅读-Profiler

本文主要针对阅读UE4源码中Profiler工具的相关的源码记录的笔记。

源码版本: UE 4.20
源码路径: Epic Games\Engine\UE_4.20\Engine\Source\Developer\Profiler\Public

目录结构:

  • Public
    • ProfilerCommon.h
    • ProfilerModule.h
  • Private
    • ProfilerModule.cpp
    • ProfilerManager.cpp
    • ProfilerSession.cpp
    • ProfilerCommands.cpp
    • Widgets
      • SProfilerWindow.cpp
      • SProfilerToolbar.cpp
      • SProfilerMiniView.cpp
      • SMultiDumpBrowser.cpp
      • SFiltersAndPresets.cpp
      • SProfilerGraphPanel.cpp
      • SDataGraph.cpp
      • SEventGraph.cpp
      • SProfilerThreadView.cpp // TODO

ProfilerModule

  • CreateProfilerWindow
    • FProfilerManager::Initialize(SessionManager)
    • SNew( SProfilerWindow )
    • FProfilerManager->AssignProfilerWindow ( ProfilerWindow )
  • ShutdownModule
    • FProfilerManager->Shutdown()
  • StatsMemoryDumpCommand // TODO

ProfilerModule::CreateProfilerWindow函数来模块的入口, 唯一的调用者为:
SSessionFrontend.cpp line 207

       else if (TabIdentifier == ProfilerTabId)
       {
              IProfilerModule& ProfilerModule = FModuleManager::LoadModuleChecked(TEXT("Profiler"));
              TabWidget = ProfilerModule.CreateProfilerWindow(SessionManager.ToSharedRef(), DockTab);

即打开Profiler窗口时, 传入的SessionManager, 包含了当前载入的会话情况(可能是live, 可能是打开的Stats文件等情况)

ProfilerWindow

主窗口, 继承于 SCompoundWidget

Construct

布局结构:

  • SOverlay
    • SVerticalBox
      • SHorizontalBox(autoHeight)
        • SProfilerToolbar
      • SBox
        • SHorizontalBox
          • SProfilerMiniView
      • SSpitter (horizontal )
        • SSpitter(0.25 Vertical)
          • SVerticalBox(0.25)
            • SHorizontalBox
              • SImage
              • STextBlock("Stats dump browser")
            • MultiDumpBrowser
          • SVerticalBox(0.75)
            • SHorizontalBox
              • SImage
              • STextBlock("Filters And Presets")
            • SFiltersAndPresets
        • SSplitter(0.75 Vertical)
          • SVerticalBox(0.25)
            • SHorizontalBox
              • SImage
              • STextBlock("Graph View")
            • SProfilerGraphPanel
          • SVerticalBox(EventGraphPanel) (0.75)
    • SBorder
      • STextBlock ( Please select a session from the Session Brower or load a saved capture )
    • SNotificationList
    • Expose OverlaySettingsSlot

截图:

2018-08-20_06-28-05.png

主要内置Widget:

  • SOverlay 框架布局
  • SVerticalBox 竖向线性布局
  • SHorizontalBox 横向线性布局
  • SSpitter 按比例分隔布局
  • SImage 图片控件
  • STextBlock 文本控件

自定义Widget:

  • ProfilerToolbar 工具栏
  • ProfilerMiniView
  • SMultiDumpBrowser
  • SFiltersAndPresets
  • SProfilerGraphPanel
  • EventGraphPanel

关键属性:

  • AutoWidth 宽度自适应
  • AutoHeight 高度自适应
  • FillWidth(1.0f) 宽度填充为父元素大小
  • FillHeight(1.0f) 高度填充父元素剩余最大
  • Padding(left, top, right, bottom) 内边距
  • HAlign(HAlign_Fill) 横向对齐方式(铺满)
  • VAlign(VAlign_Fill) 纵向对齐方式(铺满)
  • Orientation(Orient_Vertical) 方向
  • Visibility 可见性
  • IsEnabled // TODO
  • Expose // TODO

ProfilerToolbar

工具栏, 继承于 SCompoundWidget

Construct

布局:

  • SHorizontalBox
    • SBorder
      • FToolbarBuilder.MakeWidget()

创建Command:

/** UI_COMMAND takes long for the compile to optimize */
PRAGMA_DISABLE_OPTIMIZATION
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() );


}

菜单点击回调函数:

/*-----------------------------------------------------------------------------
       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( 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;
}

创建工具栏:

       struct Local
       {
              static void FillToolbar(FToolBarBuilder& ToolbarBuilder)
              {
                     ToolbarBuilder.BeginSection("File");
                     {
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ProfilerManager_Load);
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ProfilerManager_LoadMultiple);
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ProfilerManager_Save);
                     }
                     ToolbarBuilder.EndSection();
                     ToolbarBuilder.BeginSection("Capture");
                     {
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ToggleDataPreview);
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ProfilerManager_ToggleLivePreview);
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().ToggleDataCapture);
                     }
                     ToolbarBuilder.EndSection();
                     ToolbarBuilder.BeginSection("Profilers");
                     {
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().StatsProfiler);
                            //ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().MemoryProfiler);
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().FPSChart);
                     }
                     ToolbarBuilder.EndSection();
                     ToolbarBuilder.BeginSection("Options");
                     {
                            ToolbarBuilder.AddToolBarButton(FProfilerCommands::Get().OpenSettings);
                     }
                     ToolbarBuilder.EndSection();
              }
       };


        TSharedPtr ProfilerCommandList = FProfilerManager::Get()->GetCommandList();
       FToolBarBuilder ToolbarBuilder(ProfilerCommandList.ToSharedRef(), FMultiBoxCustomization::None);
       Local::FillToolbar(ToolbarBuilder);

按钮样式:
注意按钮的样式是在 UE_4.20\Engine\Source\Editor\EditorStyle\Private\SlateEditorStyle.cpp 统一设置的:

Set( "ProfilerCommand.ToggleDataPreview", new IMAGE_BRUSH( "Icons/Profiler/profiler_sync_40x", Icon40x40 ) );
Set( "ProfilerCommand.ToggleDataPreview.Small", new IMAGE_BRUSH( "Icons/Profiler/profiler_sync_40x", Icon20x20 ) );

ProfilerMiniView

Widget used to present thread data in the mini-view., 继承于 SCompoundWidget

2018-08-20_06-28-05-2.png

Tick

检查Geometry是否变化了(大小, 尺寸), 则置 bUpdateData = true

如果bUpdateData为true, 则调用 ProcessData() 来重新处理数据

OnPaint

类似于其他框架的 OnDraw,

传入的参数:

  • Args All the arguments necessary to paint this widget
  • AllottedGeometry 大小 The FGeometry that describes an area in which the widget should appear.
  • MyCullingRect The rectangle representing the bounds currently being used to completely cull widgets. Unless IsChildWidgetCulled(...) returns true, you should paint the widget.
  • OutDrawElements A list of FDrawElements to populate with the output.
  • LayerId (层的ID, 越大越靠近用户)
  • InWidgetStyle Color and Opacity to be applied to all the descendants of the widget being painted
  • bParentEnabled True if the parent of this widget is enabled.父元素是否enable

画图的函数:

  • FSlateDrawElement::MakeBox 绘制矩形
  • FSlateDrawElement::MakeText 绘制文字

MakeBox参数:

  • ElementList The list in which to add elements
  • InLayer The layer to draw the element on
  • PaintGeometry DrawSpace position and dimensions; see FPaintGeometry
  • InBrush Brush to apply to this element
  • InClippingRect Parts of the element are clipped if it falls outside of this rectangle
  • InDrawEffects Optional draw effects to apply
  • InTint Color to tint the element

这里的PaintGenmetry都是基于父元素的:

AllottedGeometry.ToPaintGeometry( FVector2D( 0, 0 ), FVector2D( MiniViewSizeX, AllottedGeometry.Size.Y ) ),
第一个FVector为offset, 第二个FVector为size

x, y的坐标系是:
-----------> (x 轴)
|
|
|
v
(y 轴)

鼠标事件 // TODO
Drop的事件因为涉及到很多计算, 暂时略过, 基本思路和其他框架的处理差不多, onMouseDown 开始处理, onMouseMove 开始移动, onMouseUp 结束移动.

MultiDumpBrowser

A custom widget used to display a histogram. 继承于 SCompoundWidget

Construct

布局:

  • SOverlay
    • SVerticalBox
      • SBorder
        • SHorizontalBox
          • STextBlock ("Show thread totals for:")
          • SEditableTextBox
    • SBorder
      • SListView(每行元素就是一个 STextBlock, 显示一个文字)

ListView

创建ListView:

SAssignNew(FileList, SListView>
    .ItemHeight(16)
    .ListItemsSource(&StatsFiles)
    .OnGenerateRow(this, &SMultiDumpBrowser::GenerateFileRow)
    .OnSelectionChanged(this, &SMultiDumpBrowser::SelectionChanged)

数据源: ListItemsSource
创建每一列的View: OnGenerateRow
点击选中回调函数: OnSelectionChanged

TSharedRef SMultiDumpBrowser::GenerateFileRow(TSharedPtr FileItem, const TSharedRef& OwnerTable)
{
    return SNew(SFileTableRow, OwnerTable, FileItem);
}




class SFileTableRow : public STableRow>
{
              void Construct(const FArguments& InArgs, const TSharedRef& OwnerTable, const TSharedPtr& InFileDesc)
              {
                     STableRow>::Construct(STableRow>::FArguments(), OwnerTable);
                     Desc = InFileDesc;
                     ChildSlot
                           [
                                  SNew(SBox)
                                  [
                                         SNew(STextBlock)
                                         .Text(this, &SFileTableRow::GetDisplayName)
                                  ]
                           ];
              }
}

每一行的Widget需要继承于SFileTableRow即可.

FiltersAndPresets

Configurable window with advanced options for filtering and creating presets.. 继承于 SCompoundWidget

Construct

布局:

  • SVerticalBox
    • SBorder
      • SVerticalBox
        • SSearchBox
        • SVerticalBox
          • SHorizontalBox
            • STextBlock("Group by")
            • SComboBox
          • SHorizontalBox
            • STextBlock("Sort by")
            • SComboBox
          • SHorizontalBox
            • SCheckBox
              • SHorizontalBox
                • SImage
                • STextBlock("HierarchicalTime")
            • SCheckBox("NumberFloat")
            • SCheckBox("NumberInt")
            • SCheckBox("Memory")
        • SBorder
          • STreeView ( gruops tree )

截图:

2018-08-20_06-28-05-3.png

STreeView

SAssignNew( GroupAndStatTree, STreeView< FGroupOrStatNodePtr > )
 .SelectionMode(ESelectionMode::Single)   // 单选模式
 .TreeItemsSource( &FilteredGroupNodes )   // 数据源
 .OnGetChildren( this, &SFiltersAndPresets::GroupAndStatTree_OnGetChildren )   // 获取树的子元素回调函数
 .OnGenerateRow( this, &SFiltersAndPresets::GroupAndStatTree_OnGenerateRow )   // 生成每一列回调函数
 .OnMouseButtonDoubleClick( this, &SFiltersAndPresets::GroupAndStatTree_OnMouseButtonDoubleClick )  // 鼠标双击回调函数
 //.OnSelectionChanged( this, &SFiltersAndPresets::GroupAndStatTree_OnSelectionChanged )
 .ItemHeight( 12 )

创建子元素

TSharedRef< ITableRow > SFiltersAndPresets::GroupAndStatTree_OnGenerateRow( FGroupOrStatNodePtr GroupOrStatNode, const TSharedRef< STableViewBase >& OwnerTable )
{
       TSharedRef< ITableRow > TableRow =
              SNew(SGroupAndStatTableRow, OwnerTable, GroupOrStatNode.ToSharedRef())
              .OnShouldBeEnabled( this, &SFiltersAndPresets::GroupAndStatTableRow_ShouldBeEnabled )
              .HighlightText( this, &SFiltersAndPresets::GroupAndStatTableRow_GetHighlightText );

       return TableRow;
}

子元素必须继承于 STableRow

/** Widget that represents a table row in the groups and stats' tree control.  Generates widgets for each column on demand. */
class SGroupAndStatTableRow : public STableRow< FGroupOrStatNodePtr >
{
    void Construct( const FArguments& InArgs, const TSharedRef& InOwnerTableView, const TSharedRef& InGroupOrStatNode )
    {

    }
}

子元素布局:

  • ChildSlot
    • SHorizontalBox
      • SExpanderArrow ( Expander arrow)
      • SImage ( Icon to visualize group or stat type)
      • STextBlock (description text)
      • SIMage (tooltip hit icon )

SExpanderArrow展开的箭头, 支持按层级缩进., 这是一个Slate库里公共的类, 路径在:
Epic Games\Engine\UE_4.20\Engine\Source\Runtime\Slate\Public\Widgets\Views\SExpanderArrow.h

ProfilerGraphPanel

A custom widget that acts as a container for widgets like SDataGraph or SEventTree., 继承于SCompoundWidget.

Construct

布局:

  • SBorder
    • SHorizontalBox
      • SVerticalBox
        • SDataGraph
        • SProfilerThreadView
        • SScrollBar (horizontal )
      • SScrollBar ( vertical )

SDataGraph

A custom widget used to display graphs., 继承于SCompoundWidget

TODO: 具体计算没细看, 主要是计算每一个points, 然后调用 MakeLines 传入points, 则会自动把这些点连着绘制成一条线

截图:

2018-08-20_06-28-05-4.png

SEventGraph

A custom event graph widget used to visualize profiling data. 继承于SCompoundWidget.

Construct

布局:

  • Splitter
    • SVerticalBox(0.5)
      • SBorder
        • SVerticalBox
          • SHorizontalBox
            • EventGraphTypes Widget
            • EventGraphViewModes Widget
            • BoxForOptions Widget
          • SHorizontalBox
            • ThreadFilter Widget
          • SBox (FunctionDetailsBox
            • SBorder
              • SHorizontalBox
                • VerticalBox ( calling functions )
              • SHorizontalBox
                • VerticalBox ( current unctions )
              • SHorizontalBox
                • VerticalBox ( called functions )
    • SBorder(0.5)
      • SHorizontalBox
        • STreeView
        • SBox
          • ExternalScrollbar

截图:

2018-08-20_06-28-05-5.png

TreeView

SAssignNew(TreeView_Base, STreeView)
    .ExternalScrollbar(ExternalScrollbar)
    .SelectionMode(ESelectionMode::Multi)
    .TreeItemsSource(&StaticEventArray)
    .OnGetChildren(this, &SEventGraph::EventGraph_OnGetChildren)
    .OnGenerateRow(this, &SEventGraph::EventGraph_OnGenerateRow)
    .OnSelectionChanged(this, &SEventGraph::EventGraph_OnSelectionChanged)
    .OnContextMenuOpening(FOnContextMenuOpening::CreateSP(this, &SEventGraph::EventGraph_GetMenuContent))
.ItemHeight(12.0f)
    .HeaderRow
    (
     SAssignNew(TreeViewHeaderRow,SHeaderRow)
     .Visibility(EVisibility::Visible)
    )




InitializeAndShowHeaderColumns();

class SEventGraphTableRow : public SMultiColumnTableRow < FEventGraphSamplePtr >

ProfilerSession

session type:

  • live
  • StatsFile
  • StatsFileRaw
  • ...

NOTE ATTRIBUTES

Created Date: 2018-08-20 06:28:05
Last Evernote Update Date: 2018-08-22 08:38:21

你可能感兴趣的:(UE4源码阅读-Profiler)