719 lines
22 KiB
C++
719 lines
22 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Widgets/SProfilerMiniView.h"
|
|
|
|
#if STATS
|
|
|
|
#include "Fonts/SlateFontInfo.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Rendering/DrawElements.h"
|
|
#include "Brushes/SlateColorBrush.h"
|
|
#include "Fonts/FontMeasure.h"
|
|
#include "Styling/CoreStyle.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "ProfilerSession.h"
|
|
#include "ProfilerStyle.h"
|
|
|
|
|
|
SProfilerMiniView::SProfilerMiniView()
|
|
: bIsActiveTimerRegistered( false )
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
SProfilerMiniView::~SProfilerMiniView()
|
|
{
|
|
|
|
}
|
|
|
|
void SProfilerMiniView::Construct( const FArguments& InArgs )
|
|
{
|
|
BindCommands();
|
|
}
|
|
|
|
void SProfilerMiniView::Reset()
|
|
{
|
|
MaxFrameTime = 0.0f;
|
|
AllFrames.Empty();
|
|
RecentlyAddedFrames.Empty();
|
|
StatMetadata = nullptr;
|
|
|
|
FMemory::Memzero( PaintStateMemory );
|
|
PaintState = nullptr;
|
|
|
|
MousePositionOnButtonDown = FVector2D::ZeroVector;
|
|
|
|
SelectionBoxFrameStart = 0;
|
|
SelectionBoxFrameEnd = 0;
|
|
|
|
HoveredFrameIndex = 0;
|
|
DistanceDragged = 0.0f;
|
|
NumPixelsPerSample = 0;
|
|
NumPixelsPerFrame = 0.0f;
|
|
|
|
bIsLeftMousePressed = false;
|
|
bIsRightMousePressed = false;
|
|
bCanBeStartDragged = false;
|
|
bCanBeEndDragged = false;
|
|
bAllowSelectionBoxZooming = false;
|
|
|
|
CursorType = EMiniviewCursor::Default;
|
|
}
|
|
|
|
EActiveTimerReturnType SProfilerMiniView::EnsureDataUpdateDuringPreview(double InCurrentTime, float InDeltaTime)
|
|
{
|
|
if (RecentlyAddedFrames.Num() > 0)
|
|
{
|
|
bUpdateData = true;
|
|
return EActiveTimerReturnType::Continue;
|
|
}
|
|
|
|
bIsActiveTimerRegistered = false;
|
|
return EActiveTimerReturnType::Stop;
|
|
}
|
|
|
|
void SProfilerMiniView::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
{
|
|
if( ThisGeometry != AllottedGeometry )
|
|
{
|
|
// Refresh.
|
|
MaxFrameTime = 0.0f;
|
|
bUpdateData = true;
|
|
}
|
|
|
|
ThisGeometry = AllottedGeometry;
|
|
|
|
if( IsReady() )
|
|
{
|
|
NumPixelsPerFrame = (float)AllottedGeometry.Size.X / (float)AllFrames.Num();
|
|
}
|
|
|
|
if( ShouldUpdateData() )
|
|
{
|
|
ProcessData();
|
|
bUpdateData = false;
|
|
}
|
|
}
|
|
|
|
int32 SProfilerMiniView::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
|
|
{
|
|
// SCOPE_LOG_TIME_FUNC();
|
|
|
|
// Rendering info.
|
|
const bool bEnabled = ShouldBeEnabled( bParentEnabled );
|
|
const ESlateDrawEffect DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
|
|
const FSlateBrush* MiniViewArea = FProfilerStyle::Get().GetBrush( "Brushes.White25" );
|
|
const FSlateBrush* WhiteBrush = FProfilerStyle::Get().GetBrush( "Brushes.White" );
|
|
|
|
PaintState = new((void*)PaintStateMemory) FSlateOnPaintState( AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, DrawEffects );
|
|
|
|
const float MiniViewSizeX = static_cast<float>(AllottedGeometry.Size.X);
|
|
const float MiniViewSizeY = static_cast<float>(AllottedGeometry.Size.Y);
|
|
|
|
const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
|
|
FSlateFontInfo SummaryFont = FCoreStyle::GetDefaultFontStyle("Regular", 8);
|
|
const float MaxFontCharHeight = static_cast<float>(FontMeasureService->Measure( TEXT( "!" ), SummaryFont ).Y);
|
|
|
|
// Draw background.
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( MiniViewSizeX, AllottedGeometry.Size.Y ), FSlateLayoutTransform() ),
|
|
MiniViewArea,
|
|
DrawEffects,
|
|
MiniViewArea->GetTint( InWidgetStyle ) * InWidgetStyle.GetColorAndOpacityTint()
|
|
);
|
|
LayerId++;
|
|
|
|
// Draw all samples.
|
|
if( IsReady() )
|
|
{
|
|
static const FSlateColorBrush SolidWhiteBrush = FSlateColorBrush( FColorList::White );
|
|
// #Profiler 2014-04-24 move to the global scope.
|
|
const FColor GameThreadColor = FColorList::Red;
|
|
const FColor RenderThreadColor = FColorList::Blue;
|
|
const FColor OtherThreadsColor = FColorList::Grey;
|
|
|
|
const float SampleScaleY = MiniViewSizeY / MaxFrameTime;
|
|
|
|
float CurrentSamplePosX = 0;
|
|
float NextSamplePosX = GetNumPixelsPerSample();
|
|
for( const FMiniViewSample& MiniViewSample : MiniViewSamples )
|
|
{
|
|
const float AllSizeY = FMath::TruncToFloat( MiniViewSample.TotalThreadTime*SampleScaleY );
|
|
const float GTSizeY = FMath::TruncToFloat( MiniViewSample.GameThreadTime*SampleScaleY );
|
|
const float RTSizeY = FMath::TruncToFloat( MiniViewSample.RenderThreadTime*SampleScaleY );
|
|
const float OtherSizeY = AllSizeY - GTSizeY - RTSizeY;
|
|
|
|
const float DestSamplePosX0 = FMath::TruncToFloat( CurrentSamplePosX );
|
|
const float DestSamplePosX1 = FMath::TruncToFloat( NextSamplePosX );
|
|
const float DestSampleSizeX = DestSamplePosX1 - DestSamplePosX0;
|
|
|
|
// The game thread on the bottom.
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( DestSampleSizeX, GTSizeY ), FSlateLayoutTransform(FVector2D( DestSamplePosX0, MiniViewSizeY - GTSizeY )) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
GameThreadColor
|
|
);
|
|
|
|
// Next the render thread.
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( DestSampleSizeX, RTSizeY ), FSlateLayoutTransform(FVector2D( DestSamplePosX0, MiniViewSizeY - GTSizeY - RTSizeY )) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
RenderThreadColor
|
|
);
|
|
|
|
// Disabled for now.
|
|
#if 0
|
|
// Finally the others threads as one sample.
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( DestSamplePosX, MiniViewSizeY - AllSizeY ), FVector2D( DestSampleSizeX, OtherSizeY ) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
OtherThreadsColor
|
|
);
|
|
#endif // 0
|
|
|
|
CurrentSamplePosX = NextSamplePosX;
|
|
NextSamplePosX += GetNumPixelsPerSample();
|
|
}
|
|
|
|
// Draw the selection box
|
|
LayerId++;
|
|
|
|
const int32 MaxFrameIndex = AllFrames.Num() - 1;
|
|
|
|
const double SelectionBoxX0 = FMath::TruncToInt( FrameIndexToPosition( SelectionBoxFrameStart ) );
|
|
const double SelectionBoxX1 = FMath::TruncToInt( FrameIndexToPosition( SelectionBoxFrameEnd + 1 ));
|
|
|
|
if( SelectionBoxFrameStart > 0 )
|
|
{
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( SelectionBoxX0, AllottedGeometry.Size.Y ), FSlateLayoutTransform(FVector2D( 0.0, 0.0 )) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
FColorList::Grey.WithAlpha( 192 )
|
|
);
|
|
}
|
|
|
|
if( SelectionBoxFrameEnd < MaxFrameIndex )
|
|
{
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( MiniViewSizeX - SelectionBoxX1, AllottedGeometry.Size.Y ), FSlateLayoutTransform(FVector2D( SelectionBoxX1, 0.0 )) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
FColorList::Grey.WithAlpha( 192 )
|
|
);
|
|
}
|
|
|
|
// Draw the filler, to hide the difference between window's width and mini-view samples' width.
|
|
const double FillerSizeX = MiniViewSizeX - CurrentSamplePosX;
|
|
if( FillerSizeX > 0.0 )
|
|
{
|
|
const double FillerPosX0 = MiniViewSizeX - FillerSizeX;
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( FillerSizeX + 1.0, AllottedGeometry.Size.Y ), FSlateLayoutTransform(FVector2D( FillerPosX0, 0.0 )) ),
|
|
&SolidWhiteBrush,
|
|
DrawEffects,
|
|
// #Profiler: 2014-04-09 How to get this color from Slate?
|
|
FColor(96,96,96)
|
|
);
|
|
}
|
|
|
|
// Border of the selection box.
|
|
LayerId++;
|
|
FSlateDrawElement::MakeBox
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToPaintGeometry( FVector2D( SelectionBoxX1 - SelectionBoxX0, AllottedGeometry.Size.Y ), FSlateLayoutTransform(FVector2D( SelectionBoxX0, 0.0 )) ),
|
|
FProfilerStyle::Get().GetBrush( "PlainBorder" ),
|
|
DrawEffects,
|
|
FColorList::Green
|
|
);
|
|
|
|
// Draw the current mouse position with the highlighted sample.
|
|
LayerId++;
|
|
|
|
// Draw the basic information about threads and data range.
|
|
const float MarkerPosX = 4.0f;
|
|
const float MarkerPosY = 4.0f;
|
|
|
|
// Upper left
|
|
DrawText( TEXT( "Rendering thread" ), SummaryFont, FVector2D( MarkerPosX, MarkerPosY ), RenderThreadColor, FColor::Black, FVector2D( 1.0, 1.0 ) );
|
|
// Down left
|
|
DrawText( TEXT( "Game thread" ), SummaryFont, FVector2D( MarkerPosX, MiniViewSizeY - MarkerPosY - MaxFontCharHeight ), GameThreadColor, FColor::Black, FVector2D( 1.0, 1.0 ) );
|
|
|
|
// Upper right
|
|
const FString ThreadTimeMax = FString::Printf( TEXT( "%5.2f MS" ), MaxFrameTime );
|
|
const double ThreadTimeMaxSizeX = FontMeasureService->Measure( ThreadTimeMax, SummaryFont ).X;
|
|
DrawText( ThreadTimeMax, SummaryFont, FVector2D( MiniViewSizeX - ThreadTimeMaxSizeX - MarkerPosX, MarkerPosY ), FColor::White, FColor::Black, FVector2D( 1.0, 1.0 ) );
|
|
|
|
// Down right
|
|
const FString ThreadTimeMin = TEXT( "0.0 MS" );
|
|
const double ThreadTimeMinSizeX = FontMeasureService->Measure( ThreadTimeMin, SummaryFont ).X;
|
|
DrawText( ThreadTimeMin, SummaryFont, FVector2D( MiniViewSizeX - ThreadTimeMinSizeX - MarkerPosX, MiniViewSizeY - MarkerPosY - MaxFontCharHeight ), FColor::White, FColor::Black, FVector2D( 1.0, 1.0 ) );
|
|
|
|
}
|
|
|
|
#if 0/*DEBUG_PROFILER_PERFORMANCE*/
|
|
|
|
LayerId++;
|
|
// Draw debug information.
|
|
float GraphDescPosY = 0;
|
|
|
|
// Debug text.
|
|
FSlateDrawElement::MakeText
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ),
|
|
FString::Printf( TEXT( "SelectionBox FrameStart=%4i, FrameEnd=%4i (%3i) Hovered=%4i, NumPixelsPerSample=%2.1f" ), SelectionBoxFrameStart, SelectionBoxFrameEnd, SelectionBoxFrameEnd - SelectionBoxFrameStart, HoveredFrameIndex, GetNumPixelsPerSample() ),
|
|
SummaryFont,
|
|
MyCullingRect,
|
|
DrawEffects,
|
|
FLinearColor::White
|
|
);
|
|
GraphDescPosY += MaxFontCharHeight + 1.0f;
|
|
|
|
FSlateDrawElement::MakeText
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ),
|
|
FString::Printf( TEXT( "AllFrames=%4i, MiniViewSamples=%3i, MaxFrameTime=%2.0f DistanceDragged=%2.0f" ), AllFrames.Num(), MiniViewSamples.Num(), MaxFrameTime, DistanceDragged ),
|
|
SummaryFont,
|
|
MyCullingRect,
|
|
DrawEffects,
|
|
FLinearColor::White
|
|
);
|
|
GraphDescPosY += MaxFontCharHeight + 1.0f;
|
|
|
|
FSlateDrawElement::MakeText
|
|
(
|
|
OutDrawElements,
|
|
LayerId,
|
|
AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ),
|
|
FString::Printf( TEXT( "bCanBeStartD=%1i, bCanBeEndD=%1i" ), (int32)bCanBeStartDragged, (int32)bCanBeEndDragged ),
|
|
SummaryFont,
|
|
MyCullingRect,
|
|
DrawEffects,
|
|
FLinearColor::White
|
|
);
|
|
GraphDescPosY += MaxFontCharHeight + 1.0f;
|
|
|
|
#endif // DEBUG_PROFILER_PERFORMANCE
|
|
|
|
return SCompoundWidget::OnPaint( Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled && IsEnabled() );
|
|
}
|
|
|
|
|
|
void SProfilerMiniView::DrawText( const FString& Text, const FSlateFontInfo& FontInfo, FVector2D Position, const FColor& TextColor, const FColor& ShadowColor, FVector2D ShadowOffset ) const
|
|
{
|
|
if( ShadowOffset.SizeSquared() > 0.0f )
|
|
{
|
|
FSlateDrawElement::MakeText
|
|
(
|
|
PaintState->OutDrawElements,
|
|
PaintState->LayerId,
|
|
PaintState->AllottedGeometry.ToOffsetPaintGeometry( Position + ShadowOffset ),
|
|
Text,
|
|
FontInfo,
|
|
PaintState->DrawEffects,
|
|
ShadowColor
|
|
);
|
|
}
|
|
|
|
FSlateDrawElement::MakeText
|
|
(
|
|
PaintState->OutDrawElements,
|
|
++PaintState->LayerId,
|
|
PaintState->AllottedGeometry.ToOffsetPaintGeometry( Position ),
|
|
Text,
|
|
FontInfo,
|
|
PaintState->DrawEffects,
|
|
TextColor
|
|
);
|
|
}
|
|
|
|
|
|
FReply SProfilerMiniView::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
FReply Reply = FReply::Unhandled();
|
|
|
|
if( IsReady() )
|
|
{
|
|
MousePositionOnButtonDown = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
|
|
|
|
if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
|
|
{
|
|
bIsLeftMousePressed = true;
|
|
|
|
if( bCanBeStartDragged )
|
|
{
|
|
DistanceDragged = FrameIndexToPosition( SelectionBoxFrameStart );
|
|
}
|
|
else if( bCanBeEndDragged )
|
|
{
|
|
DistanceDragged = FrameIndexToPosition( SelectionBoxFrameEnd );
|
|
}
|
|
else
|
|
{
|
|
// Clicked outside the selection box, so move the selection box to that position.
|
|
DistanceDragged = static_cast<float>(MousePositionOnButtonDown.X);
|
|
}
|
|
|
|
if( bCanBeStartDragged || bCanBeEndDragged )
|
|
{
|
|
// Capture mouse, so we can move outside this widget.
|
|
Reply = FReply::Handled().CaptureMouse( SharedThis( this ) );
|
|
}
|
|
}
|
|
else if( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton )
|
|
{
|
|
bIsRightMousePressed = true;
|
|
}
|
|
}
|
|
|
|
return Reply;
|
|
}
|
|
|
|
FReply SProfilerMiniView::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
FReply Reply = FReply::Unhandled();
|
|
|
|
if( IsReady() )
|
|
{
|
|
const FVector2D MousePositionOnButtonUp = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
|
|
const bool bIsValidForMouseClick = MousePositionOnButtonUp.Equals( MousePositionOnButtonDown, MOUSE_SNAP_DISTANCE );
|
|
|
|
if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
|
|
{
|
|
if( bIsLeftMousePressed )
|
|
{
|
|
if( !bCanBeStartDragged && !bCanBeEndDragged )
|
|
{
|
|
MoveSelectionBox( PositionToFrameIndex( DistanceDragged ) );
|
|
}
|
|
else if( bCanBeStartDragged || bCanBeEndDragged )
|
|
{
|
|
// Release the mouse, we are no longer dragging.
|
|
Reply = FReply::Handled().ReleaseMouseCapture();
|
|
}
|
|
}
|
|
|
|
bIsLeftMousePressed = false;
|
|
}
|
|
else if( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton )
|
|
{
|
|
if( bIsRightMousePressed )
|
|
{
|
|
if( bIsValidForMouseClick )
|
|
{
|
|
ShowContextMenu( MouseEvent.GetScreenSpacePosition() );
|
|
Reply = FReply::Handled();
|
|
}
|
|
}
|
|
bIsRightMousePressed = false;
|
|
}
|
|
}
|
|
|
|
return Reply;
|
|
}
|
|
|
|
FReply SProfilerMiniView::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
// SCOPE_LOG_TIME_FUNC();
|
|
|
|
FReply Reply = FReply::Unhandled();
|
|
|
|
if( IsReady() )
|
|
{
|
|
const FVector2D MousePosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
|
|
HoveredFrameIndex = PositionToFrameIndex( static_cast<float>(MousePosition.X) );
|
|
|
|
const float CursorPosXDelta = static_cast<float>(MouseEvent.GetCursorDelta().X);
|
|
|
|
if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) )
|
|
{
|
|
if( HasMouseCapture() && !MouseEvent.GetCursorDelta().IsZero() )
|
|
{
|
|
DistanceDragged += CursorPosXDelta;
|
|
|
|
const int32 MouseFrameIndex = PositionToFrameIndex( DistanceDragged );
|
|
|
|
if( !bAllowSelectionBoxZooming )
|
|
{
|
|
const int32 SelectionBoxSize = SelectionBoxFrameEnd - SelectionBoxFrameStart;
|
|
if( bCanBeStartDragged )
|
|
{
|
|
SelectionBoxFrameStart = MouseFrameIndex;
|
|
SelectionBoxFrameStart = FMath::Clamp( SelectionBoxFrameStart, 0, FMath::Max( AllFrames.Num() - SelectionBoxSize - 1, 0 ) );
|
|
SelectionBoxFrameEnd = FMath::Min( SelectionBoxFrameStart + SelectionBoxSize, AllFrames.Num() - 1 );
|
|
}
|
|
else if( bCanBeEndDragged )
|
|
{
|
|
SelectionBoxFrameEnd = MouseFrameIndex;
|
|
SelectionBoxFrameEnd = FMath::Clamp( SelectionBoxFrameEnd, SelectionBoxSize - 1, AllFrames.Num() - -1 );
|
|
SelectionBoxFrameStart = FMath::Max( SelectionBoxFrameEnd - SelectionBoxSize, 0 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
// Inform other widgets that we have moved the selection box.
|
|
SelectionBoxChangedEvent.Broadcast( SelectionBoxFrameStart, SelectionBoxFrameEnd );
|
|
|
|
Reply = FReply::Handled();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const float StartEdgeDistance = FrameIndexToPosition(SelectionBoxFrameStart) - static_cast<float>(MousePosition.X);
|
|
const float EndEdgeDistance = static_cast<float>(MousePosition.X) - FrameIndexToPosition(SelectionBoxFrameEnd);
|
|
|
|
bCanBeStartDragged = StartEdgeDistance < (float)MOUSE_SNAP_DISTANCE && StartEdgeDistance > 0.0f;
|
|
bCanBeEndDragged = EndEdgeDistance < (float)MOUSE_SNAP_DISTANCE && EndEdgeDistance > 0.0f;
|
|
|
|
if( StartEdgeDistance <= 0.0f && EndEdgeDistance <= 0.0f )
|
|
{
|
|
// Drag the whole selection box.
|
|
bCanBeStartDragged = true;
|
|
bCanBeEndDragged = true;
|
|
CursorType = EMiniviewCursor::Hand;
|
|
}
|
|
else if( bCanBeStartDragged != bCanBeEndDragged )
|
|
{
|
|
CursorType = EMiniviewCursor::Arrow;
|
|
}
|
|
else
|
|
{
|
|
CursorType = EMiniviewCursor::Default;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Reply;
|
|
}
|
|
|
|
void SProfilerMiniView::OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
|
|
}
|
|
|
|
void SProfilerMiniView::OnMouseLeave( const FPointerEvent& MouseEvent )
|
|
{
|
|
if( !HasMouseCapture() )
|
|
{
|
|
bIsLeftMousePressed = false;
|
|
bIsRightMousePressed = false;
|
|
|
|
bCanBeStartDragged = false;
|
|
bCanBeEndDragged = false;
|
|
|
|
CursorType = EMiniviewCursor::Default;
|
|
}
|
|
}
|
|
|
|
FReply SProfilerMiniView::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
FReply Reply = FReply::Unhandled();
|
|
return Reply;
|
|
}
|
|
|
|
FReply SProfilerMiniView::OnMouseButtonDoubleClick( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
FReply Reply = FReply::Unhandled();
|
|
return Reply;
|
|
}
|
|
|
|
|
|
FCursorReply SProfilerMiniView::OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const
|
|
{
|
|
FCursorReply CursorReply = FCursorReply::Unhandled();
|
|
if( CursorType == EMiniviewCursor::Arrow )
|
|
{
|
|
CursorReply = FCursorReply::Cursor( EMouseCursor::ResizeLeftRight );
|
|
}
|
|
else if( CursorType == EMiniviewCursor::Hand )
|
|
{
|
|
CursorReply = FCursorReply::Cursor( EMouseCursor::GrabHand );
|
|
}
|
|
return CursorReply;
|
|
}
|
|
|
|
void SProfilerMiniView::ShowContextMenu( const FVector2D& ScreenSpacePosition )
|
|
{
|
|
|
|
}
|
|
|
|
void SProfilerMiniView::BindCommands()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SProfilerMiniView::AddThreadTime( int32 InFrameIndex, const TMap<uint32, float>& InThreadMS, const TSharedRef<FProfilerStatMetaData>& InStatMetaData )
|
|
{
|
|
FFrameThreadTimes FrameThreadTimes;
|
|
FrameThreadTimes.FrameNumber = InFrameIndex;
|
|
FrameThreadTimes.ThreadTimes = InThreadMS;
|
|
RecentlyAddedFrames.Add( FrameThreadTimes );
|
|
|
|
if (!bIsActiveTimerRegistered)
|
|
{
|
|
bIsActiveTimerRegistered = true;
|
|
RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SProfilerMiniView::EnsureDataUpdateDuringPreview));
|
|
}
|
|
|
|
StatMetadata = InStatMetaData;
|
|
}
|
|
|
|
void SProfilerMiniView::MoveWithoutZoomSelectionBox( int32 FrameStart, int32 FrameEnd )
|
|
{
|
|
const int32 MaxFrameIndex = FMath::Max( AllFrames.Num() - 1, 0 );
|
|
SelectionBoxFrameStart = FMath::Clamp( FrameStart, 0, MaxFrameIndex );
|
|
SelectionBoxFrameEnd = FMath::Clamp( FrameEnd, 0, MaxFrameIndex );
|
|
bAllowSelectionBoxZooming = false;
|
|
}
|
|
|
|
|
|
void SProfilerMiniView::MoveAndZoomSelectionBox( int32 FrameStart, int32 FrameEnd )
|
|
{
|
|
const int32 MaxFrameIndex = FMath::Max( AllFrames.Num() - 1, 0 );
|
|
SelectionBoxFrameStart = FMath::Clamp( FrameStart, 0, MaxFrameIndex );
|
|
SelectionBoxFrameEnd = FMath::Clamp( FrameEnd, 0, MaxFrameIndex );
|
|
//bAllowSelectionBoxZooming = true;
|
|
}
|
|
|
|
void SProfilerMiniView::MoveSelectionBox( int32 FrameIndex )
|
|
{
|
|
const int32 SelectionBoxSize = SelectionBoxFrameEnd - SelectionBoxFrameStart;
|
|
const int32 SelectionBoxHalfSize = SelectionBoxSize / 2;
|
|
const int32 CenterFrameIndex = FMath::Clamp( FrameIndex - SelectionBoxHalfSize, 0, AllFrames.Num() - 1 - SelectionBoxSize );
|
|
|
|
// Inform other widgets that we have moved the selection box.
|
|
SelectionBoxFrameStart = CenterFrameIndex;
|
|
SelectionBoxFrameEnd = CenterFrameIndex + SelectionBoxSize;
|
|
SelectionBoxChangedEvent.Broadcast( SelectionBoxFrameStart, SelectionBoxFrameEnd );
|
|
}
|
|
|
|
const int32 SProfilerMiniView::PositionToFrameIndex( const float InPositionX ) const
|
|
{
|
|
int32 FrameIndex = 0;
|
|
|
|
if( IsReady() )
|
|
{
|
|
const int32 NumAllFrames = AllFrames.Num();
|
|
const int32 NumMiniViewSamples = MiniViewSamples.Num();
|
|
|
|
const float ScaleRatio = (float)NumAllFrames / (float)NumMiniViewSamples;
|
|
const float MouseSampleIndex = InPositionX / GetNumPixelsPerSample();
|
|
|
|
FrameIndex = FMath::TruncToInt(MouseSampleIndex * ScaleRatio);
|
|
FrameIndex = FMath::Clamp( FrameIndex, 0, NumAllFrames - 1 );
|
|
}
|
|
|
|
return FrameIndex;
|
|
}
|
|
|
|
|
|
void SProfilerMiniView::ProcessData()
|
|
{
|
|
static FTotalTimeAndCount TimeAndCount( 0.0f, 0 );
|
|
//SCOPE_LOG_TIME_FUNC_WITH_GLOBAL( &TimeAndCount );
|
|
|
|
AllFrames.Append( RecentlyAddedFrames );
|
|
RecentlyAddedFrames.Reset();
|
|
|
|
if( !IsReady() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateNumPixelsPerSample();
|
|
|
|
const int32 NumMiniViewSamples = FMath::TruncToInt(static_cast<float>(ThisGeometry.Size.X) / GetNumPixelsPerSample());
|
|
MiniViewSamples.Reset( NumMiniViewSamples );
|
|
|
|
MiniViewSamples.AddZeroed( NumMiniViewSamples );
|
|
const int32 NumAllFrames = AllFrames.Num();
|
|
|
|
const uint32 GameThreadID = StatMetadata->GetGameThreadID();
|
|
const TArray<uint32>& RenderThreadIDs = StatMetadata->GetRenderThreadID();
|
|
|
|
// Prepare data to fit into the window.
|
|
{
|
|
// Aggregate.
|
|
const float ScaleRatio = (float)NumMiniViewSamples / (float)NumAllFrames;
|
|
|
|
for( int32 FrameIndex = 0; FrameIndex < NumAllFrames; ++FrameIndex )
|
|
{
|
|
const FFrameThreadTimes& FrameThreadTimes = AllFrames[FrameIndex];
|
|
const int32 SampleIndex = FMath::TruncToInt( ScaleRatio * (float)FrameIndex );
|
|
|
|
FMiniViewSample& Dest = MiniViewSamples[SampleIndex];
|
|
Dest.AddFrameAndFindMax( FrameThreadTimes );
|
|
}
|
|
|
|
for( FMiniViewSample& It : MiniViewSamples )
|
|
{
|
|
It.CalculateMaxThreadTime( GameThreadID, RenderThreadIDs );
|
|
}
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
// Replicate.
|
|
const float ScaleRatio = (float)NumAllFrames / (float)WindowNumSamples;
|
|
|
|
float CurrentFrameIndex = 0.0f;
|
|
for( int32 SampleIndex = 0; SampleIndex < WindowNumSamples; ++SampleIndex )
|
|
{
|
|
const int FrameIndex = FMath::TruncToInt( CurrentFrameIndex );
|
|
const FFrameThreadTimes& FrameThreadTimes = AllFrames[FrameIndex];
|
|
|
|
FMiniViewThreadTimes& Dest = WindowFrames[SampleIndex];
|
|
Dest.Aggregate( AllFrames[FrameIndex] );
|
|
Dest.CalculateMaxThreadTime( GameThreadID, RenderThreadIDs );
|
|
|
|
CurrentFrameIndex += ScaleRatio;
|
|
}
|
|
}
|
|
#endif // 0
|
|
|
|
// Calculate max thread time, used to scaling the displayed samples.
|
|
for( const FMiniViewSample& MiniViewSample : MiniViewSamples )
|
|
{
|
|
MaxFrameTime = FMath::Max( MaxFrameTime, MiniViewSample.TotalThreadTime );
|
|
}
|
|
|
|
MaxFrameTime = FMath::Clamp( MaxFrameTime, 0.0f, (float)MAX_VISIBLE_THREADTIME );
|
|
}
|
|
|
|
#endif // STATS
|