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

324 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#if STATS
#include "Misc/Paths.h"
#include "Layout/SlateRect.h"
#include "Layout/Geometry.h"
#include "Fonts/SlateFontInfo.h"
#include "Input/CursorReply.h"
#include "Input/Reply.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
#include "Fonts/FontMeasure.h"
#include "Styling/CoreStyle.h"
#include "Framework/Application/SlateApplication.h"
#include "ProfilerStream.h"
/**
* Widget used to present thread data in the mini-view.
*/
class SProfilerThreadView
: public SCompoundWidget
{
enum
{
/** Minimum width of the one rendered sample, if less cycles counter will be combined. */
MIN_NUM_PIXELS_PER_SAMPLE = 32,
/**
* Number of milliseconds that can be renderer at once in the window.
* For the default zoom value.
*/
NUM_MILLISECONDS_PER_WINDOW = 33,
/** Number of pixels needed to render one row of cycle counter. */
NUM_PIXELS_PER_ROW = 16,
/** Number of pixels. */
MOUSE_SNAP_DISTANCE = 4,
/** Wait time in milliseconds before we display a tooltip. */
TOOLTIP_DELAY = 500,
/** Width of the thread description windows. */
WIDTH_THREAD_DESC = 128,
/**
* Displayed data will be partitioned into smaller batches to avoid long processing times.
* This should help in situation when the user scroll the thread-view, so we don't need to wait for the whole data.
* At the same it adds some overhead to the processing in favor of using massive parallel processing,
* so overall it will be faster and much more responsive.
* One partition must have a least one frame.
*/
NUM_DATA_PARTITIONS = 16,
// #Profiler: 2014-04-25 Dynamic data partitioning
/**
* Maximum zoom value for time axis.
* Default value mean that one 33ms frame can be rendered at once in the window.
* Maximum zoom allows to see individual cycles.
*/
INV_MIN_VISIBLE_RANGE_X = 10000,
MAX_VISIBLE_RANGE_X = 250,
/** Number of pixels between each time line. */
NUM_PIXELS_BETWEEN_TIMELINE = 96,
};
struct EThreadViewCursor
{
enum Type
{
Default,
Arrow,
Hand,
};
};
/** Holds current state provided by OnPaint function, used to simplify drawing. */
struct FSlateOnPaintState : public FNoncopyable
{
FSlateOnPaintState( const FGeometry& InAllottedGeometry, const FSlateRect& InMyCullingRect, FSlateWindowElementList& InOutDrawElements, int32& InLayerId, const FWidgetStyle& InWidgetStyle, ESlateDrawEffect InDrawEffects )
: AllottedGeometry( InAllottedGeometry )
, AbsoluteClippingRect( InMyCullingRect )
, LocalClippingRect( FVector2D::ZeroVector, InAllottedGeometry.GetLocalSize() )
, WidgetStyle( InWidgetStyle )
, OutDrawElements( InOutDrawElements )
, LayerId( InLayerId )
, DrawEffects( InDrawEffects )
, FontMeasureService( FSlateApplication::Get().GetRenderer()->GetFontMeasureService() )
, SummaryFont8( FCoreStyle::GetDefaultFontStyle("Regular", 8) )
, SummaryFont8Height( static_cast<float>(FontMeasureService->Measure( TEXT( "!" ), SummaryFont8 ).Y) )
{}
FVector2f Size2D() const
{
return AllottedGeometry.GetLocalSize();
}
/** Accessors. */
const FGeometry& AllottedGeometry;
const FSlateRect& AbsoluteClippingRect;
const FSlateRect LocalClippingRect;
const FWidgetStyle& WidgetStyle;
FSlateWindowElementList& OutDrawElements;
int32& LayerId;
const ESlateDrawEffect DrawEffects;
const TSharedRef< FSlateFontMeasure > FontMeasureService;
const FSlateFontInfo SummaryFont8;
const float SummaryFont8Height;
};
public:
SProfilerThreadView();
~SProfilerThreadView();
SLATE_BEGIN_ARGS( SProfilerThreadView )
{}
SLATE_END_ARGS()
/**
* Construct this widget
*
* @param InArgs The declaration data for this widget
*/
void Construct( const FArguments& InArgs );
/** Resets internal widget's data to the default one. */
void Reset();
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual void OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual void OnMouseLeave( const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseButtonDoubleClick( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FCursorReply OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const override;
void ShowContextMenu( const FVector2D& ScreenSpacePosition );
/** Binds UI commands to delegates. */
void BindCommands();
void DrawText( const FString& Text, const FSlateFontInfo& FontInfo, FVector2D Position, const FColor& TextColor, const FColor& ShadowColor, FVector2D ShadowOffset, const FSlateRect* ClippingRect = nullptr ) const;
void DrawUIStackNodes_Recursively( const FProfilerUIStackNode& UIStackNode ) const;
void DrawFramesBackgroundAndTimelines() const;
void DrawUIStackNodes() const;
void DrawFrameMarkers() const;
public:
/**
* Changes the position-x of the thread view.
* Called by the horizontal scroll bar.
*/
void SetPositionXToByScrollBar( double ScrollOffset );
void SetPositionX( double NewPositionXMS );
/**
* Changes the position-y of the thread view.
* Called by the external code.
*/
void SetPositonYTo( double ScrollOffset );
/** Changes the position-x and range-x of the thread view. */
void SetTimeRange( double StartTimeMS, double EndTimeMS, bool bBroadcast = true );
/**
* Changes the position-x and range-x of the thread view.
* Called by the mini-view.
*/
void SetFrameRange( int32 FrameStart, int32 FrameEnd );
/** Attaches profiler stream to the thread-view widgets and displays the first frame of data. */
void AttachProfilerStream( const FProfilerStream& InProfilerStream );
public:
/** The event to execute when the position-x of the thread view has been changed. */
DECLARE_EVENT_FiveParams( SProfilerThreadView, FViewPositionXChangedEvent, double /*StartTimeMS*/, double /*EndTimeMS*/, double /*MaxEndTimeMS*/, int32 /*FrameStart*/, int32 /*FrameEnd*/ );
FViewPositionXChangedEvent& OnViewPositionXChanged()
{
return ViewPositionXChangedEvent;
}
protected:
/** The event to execute when the position-x of the thread view has been changed. */
FViewPositionXChangedEvent ViewPositionXChangedEvent;
public:
/** The event to execute when the position-y of the thread view has been changed. */
DECLARE_EVENT_ThreeParams( SProfilerThreadView, FViewPositionYChangedEvent, double /*PosYStart*/, double /*PosYEnd*/, double /*MaxPosY*/ );
FViewPositionYChangedEvent& OnViewPositionYChanged()
{
return ViewPositionYChangedEvent;
}
protected:
/** The event to execute when the position-y of the thread view has been changed. */
FViewPositionYChangedEvent ViewPositionYChangedEvent;
protected:
/**
* @return True, if the widget is ready to use, also means that contains at least one frame of the thread data.
*/
bool IsReady() const;
void ProcessData();
bool ShouldUpdateData();
void UpdateInternalConstants();
protected:
/*-----------------------------------------------------------------------------
Data variables
-----------------------------------------------------------------------------*/
/** Profiler UI stream, contains data optimized for displaying in this widget. */
FProfilerUIStream ProfilerUIStream;
/** Pointer to the profiler stream, used as a source for the UI stream. */
const FProfilerStream* ProfilerStream;
/*-----------------------------------------------------------------------------
UI variables
-----------------------------------------------------------------------------*/
FGeometry ThisGeometry;
/** Current Slate OnPaint state. */
uint8 PaintStateMemory[sizeof(FSlateOnPaintState)];
mutable FSlateOnPaintState* PaintState;
/** The current mouse position. */
FVector2D MousePosition;
/** The last mouse position. */
FVector2D LastMousePosition;
/** Mouse position during the call on mouse button down. */
FVector2D MousePositionOnButtonDown;
/** Position-X of the thread view, in milliseconds. */
double PositionXMS;
/** Position-Y of the thread view, where 1.0 means one row of the data. */
double PositionY;
/** Range of the visible data for the current zoom, in milliseconds. */
double RangeXMS;
/** Range of the visible data. */
double RangeY;
/** Range of the all collected data, in milliseconds. */
double TotalRangeXMS;
/** Range of the all collected data. */
double TotalRangeY;
/** Current zoom value for X. */
double ZoomFactorX;
/** Number of milliseconds that can be renderer at once in the window. */
double NumMillisecondsPerWindow;
/** Number of pixels needed to render one millisecond cycle counter. */
double NumPixelsPerMillisecond;
/** Number of milliseconds that can be displayed as one cycle counter. */
double NumMillisecondsPerSample;
/** Index of the frame currently being hovered by the mouse. */
int32 HoveredFrameIndex;
/** Thread ID currently being hovered by the mouse. */
int32 HoveredThreadID;
/** Position-Y of the thread view currently being hovered by the mouse, in milliseconds. */
double HoveredPositionX;
/** Position-Y of the thread view currently being hovered by the mouse. */
double HoveredPositionY;
/** Distance dragged. */
double DistanceDragged;
/** Frame indices of the currently visible data. X= FrameStart, Y=FrameEnd+1 */
FIntPoint FramesIndices;
bool bIsLeftMousePressed;
bool bIsRightMousePressed;
/** Whether to updated data. */
bool bUpdateData;
/** Cursor type. */
EThreadViewCursor::Type CursorType;
};
#endif // STATS