EM_Task/TraceInsights/Private/Insights/NetworkingProfiler/ViewModels/PacketViewDrawHelper.cpp

304 lines
12 KiB
C++
Raw Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "PacketViewDrawHelper.h"
#include "Framework/Application/SlateApplication.h"
#include "Rendering/DrawElements.h"
#include "TraceServices/AnalysisService.h"
// Insights
#include "Insights/Common/PaintUtils.h"
#include "Insights/InsightsStyle.h"
#include "Insights/NetworkingProfiler/ViewModels/PacketViewport.h"
#include "Insights/ViewModels/DrawHelpers.h"
#include <limits>
////////////////////////////////////////////////////////////////////////////////////////////////////
// FNetworkPacketAggregatedSample
////////////////////////////////////////////////////////////////////////////////////////////////////
void FNetworkPacketAggregatedSample::AddPacket(const int32 PacketIndex, const Trace::FNetProfilerPacket& Packet)
{
NumPackets++;
const double TimeStamp = static_cast<double>(Packet.TimeStamp);
if (TimeStamp < StartTime)
{
StartTime = TimeStamp;
}
if (TimeStamp > EndTime)
{
EndTime = TimeStamp;
}
if (Packet.TotalPacketSizeInBytes > LargestPacket.TotalSizeInBytes)
{
LargestPacket.Index = PacketIndex;
LargestPacket.SequenceNumber = Packet.SequenceNumber;
LargestPacket.ContentSizeInBits = Packet.ContentSizeInBits;
LargestPacket.TotalSizeInBytes = Packet.TotalPacketSizeInBytes;
LargestPacket.TimeStamp = TimeStamp;
LargestPacket.Status = Packet.DeliveryStatus;
}
switch (AggregatedStatus)
{
case Trace::ENetProfilerDeliveryStatus::Unknown:
AggregatedStatus = Packet.DeliveryStatus;
break;
case Trace::ENetProfilerDeliveryStatus::Dropped:
break;
case Trace::ENetProfilerDeliveryStatus::Delivered:
if (Packet.DeliveryStatus == Trace::ENetProfilerDeliveryStatus::Dropped)
{
AggregatedStatus = Trace::ENetProfilerDeliveryStatus::Dropped;
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// FNetworkPacketSeriesBuilder
////////////////////////////////////////////////////////////////////////////////////////////////////
FNetworkPacketSeriesBuilder::FNetworkPacketSeriesBuilder(FNetworkPacketSeries& InSeries, const FPacketViewport& InViewport)
: Series(InSeries), Viewport(InViewport), NumAddedPackets(0)
{
SampleW = Viewport.GetSampleWidth();
PacketsPerSample = Viewport.GetNumPacketsPerSample();
NumSamples = FMath::Max(0, FMath::CeilToInt(Viewport.GetWidth() / SampleW));
FirstPacketIndex = Viewport.GetFirstPacketIndex();
Series.NumAggregatedPackets = 0;
Series.Samples.Reset();
Series.Samples.AddDefaulted(NumSamples);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FNetworkPacketAggregatedSample* FNetworkPacketSeriesBuilder::AddPacket(const int32 PacketIndex, const Trace::FNetProfilerPacket& Packet)
{
NumAddedPackets++;
int32 SampleIndex = (PacketIndex - FirstPacketIndex) / PacketsPerSample;
if (SampleIndex >= 0 && SampleIndex < NumSamples)
{
FNetworkPacketAggregatedSample& Sample = Series.Samples[SampleIndex];
Sample.AddPacket(PacketIndex, Packet);
Series.NumAggregatedPackets++;
return &Sample;
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// FPacketViewDrawHelper
////////////////////////////////////////////////////////////////////////////////////////////////////
FPacketViewDrawHelper::FPacketViewDrawHelper(const FDrawContext& InDrawContext, const FPacketViewport& InViewport)
: DrawContext(InDrawContext), Viewport(InViewport), WhiteBrush(FInsightsStyle::Get().GetBrush("WhiteBrush"))
//, EventBorderBrush(FInsightsStyle::Get().GetBrush("EventBorder"))
,
HoveredEventBorderBrush(FInsightsStyle::Get().GetBrush("HoveredEventBorder")),
SelectedEventBorderBrush(FInsightsStyle::Get().GetBrush("SelectedEventBorder")),
SelectionFont(FCoreStyle::GetDefaultFontStyle("Regular", 8)),
NumPackets(0),
NumDrawSamples(0)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FPacketViewDrawHelper::DrawBackground() const
{
const FAxisViewportInt32& ViewportX = Viewport.GetHorizontalAxisViewport();
const float X0 = 0.0f;
const float X1 = ViewportX.GetMinPos() - ViewportX.GetPos();
const float X2 = ViewportX.GetMaxPos() - ViewportX.GetPos();
const float X3 = FMath::CeilToFloat(Viewport.GetWidth());
const float Y = 0.0f;
const float H = FMath::CeilToFloat(Viewport.GetHeight());
FDrawHelpers::DrawBackground(DrawContext, WhiteBrush, X0, X1, X2, X3, Y, H);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FLinearColor FPacketViewDrawHelper::GetColorByStatus(Trace::ENetProfilerDeliveryStatus Status)
{
constexpr float Alpha = 1.0f;
switch (Status)
{
case Trace::ENetProfilerDeliveryStatus::Unknown:
return FLinearColor(0.25f, 0.25f, 0.25f, Alpha);
case Trace::ENetProfilerDeliveryStatus::Delivered:
return FLinearColor(0.5f, 1.0f, 0.5f, Alpha);
case Trace::ENetProfilerDeliveryStatus::Dropped:
return FLinearColor(1.0f, 0.5f, 0.5f, Alpha);
default:
return FLinearColor(1.0f, 0.0f, 0.0f, Alpha);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FPacketViewDrawHelper::DrawCached(const FNetworkPacketSeries& Series) const
{
if (Series.NumAggregatedPackets == 0)
{
return;
}
NumPackets += Series.NumAggregatedPackets;
const float SampleW = Viewport.GetSampleWidth();
const int32 NumSamples = Series.Samples.Num();
const FAxisViewportDouble& ViewportY = Viewport.GetVerticalAxisViewport();
const float ViewHeight = FMath::RoundToFloat(Viewport.GetHeight());
const float BaselineY = FMath::RoundToFloat(ViewportY.GetOffsetForValue(0.0));
for (int32 SampleIndex = 0; SampleIndex < NumSamples; SampleIndex++)
{
const FNetworkPacketAggregatedSample& Sample = Series.Samples[SampleIndex];
if (Sample.NumPackets == 0)
{
continue;
}
NumDrawSamples++;
const float X = SampleIndex * SampleW;
// const float ValueY = FMath::RoundToFloat(ViewportY.GetOffsetForValue(static_cast<double>(Sample.LargestPacket.ContentSizeInBits)));
const float ValueY = FMath::RoundToFloat(ViewportY.GetOffsetForValue(static_cast<double>(Sample.LargestPacket.TotalSizeInBytes * 8)));
const float H = ValueY - BaselineY;
const float Y = ViewHeight - H;
FLinearColor ColorFill = GetColorByStatus(Sample.AggregatedStatus);
if (!Sample.bAtLeastOnePacketMatchesFilter)
{
ColorFill.A = 0.1f;
}
const FLinearColor ColorBorder(ColorFill.R * 0.75f, ColorFill.G * 0.75f, ColorFill.B * 0.75f, ColorFill.A);
if (SampleW > 2.0f)
{
DrawContext.DrawBox(X + 1.0f, Y + 1.0f, SampleW - 2.0f, H - 2.0f, WhiteBrush, ColorFill);
// Draw border.
DrawContext.DrawBox(X, Y, 1.0, H, WhiteBrush, ColorBorder);
DrawContext.DrawBox(X + SampleW - 1.0f, Y, 1.0, H, WhiteBrush, ColorBorder);
DrawContext.DrawBox(X + 1.0f, Y, SampleW - 2.0f, 1.0f, WhiteBrush, ColorBorder);
DrawContext.DrawBox(X + 1.0f, Y + H - 1.0f, SampleW - 2.0f, 1.0f, WhiteBrush, ColorBorder);
}
else
{
DrawContext.DrawBox(X, Y, SampleW, H, WhiteBrush, ColorBorder);
}
}
DrawContext.LayerId++;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FPacketViewDrawHelper::DrawSampleHighlight(const FNetworkPacketAggregatedSample& Sample, EHighlightMode Mode) const
{
const float SampleW = Viewport.GetSampleWidth();
const int32 PacketsPerSample = Viewport.GetNumPacketsPerSample();
const int32 FirstPacketIndex = Viewport.GetFirstPacketIndex();
const int32 SampleIndex = (Sample.LargestPacket.Index - FirstPacketIndex) / PacketsPerSample;
const float X = SampleIndex * SampleW;
const FAxisViewportDouble& ViewportY = Viewport.GetVerticalAxisViewport();
const float ViewHeight = FMath::RoundToFloat(Viewport.GetHeight());
const float BaselineY = FMath::RoundToFloat(ViewportY.GetOffsetForValue(0.0));
// const double Value = static_cast<double>(Sample.LargestPacket.ContentSizeInBits);
const double Value = static_cast<double>(Sample.LargestPacket.TotalSizeInBytes * 8);
const float ValueY = FMath::RoundToFloat(ViewportY.GetOffsetForValue(Value));
const float H = ValueY - BaselineY;
const float Y = ViewHeight - H;
if (Mode == EHighlightMode::Hovered)
{
const FLinearColor Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
// Draw border around the hovered box.
DrawContext.DrawBox(X - 1.0f, Y - 1.0f, SampleW + 2.0f, H + 2.0f, HoveredEventBorderBrush, Color);
}
else // EHighlightMode::Selected or EHighlightMode::SelectedAndHovered
{
// Animate color from white (if selected and hovered) or yellow (if only selected) to black, using a squared sine function.
const double Time = static_cast<double>(FPlatformTime::Cycles64()) * FPlatformTime::GetSecondsPerCycle64();
float S = FMath::Sin(2.0 * Time);
S = S * S; // squared, to ensure only positive [0 - 1] values
const float Blue = (Mode == EHighlightMode::SelectedAndHovered) ? 0.0f : S;
const FLinearColor Color(S, S, Blue, 1.0f);
// Draw border around the selected box.
DrawContext.DrawBox(X - 1.0f, Y - 1.0f, SampleW + 2.0f, H + 2.0f, SelectedEventBorderBrush, Color);
}
DrawContext.LayerId++;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FPacketViewDrawHelper::DrawSelection(int32 StartPacketIndex, int32 EndPacketIndex) const
{
const float SampleW = Viewport.GetSampleWidth();
const int32 PacketsPerSample = Viewport.GetNumPacketsPerSample();
const int32 FirstPacketIndex = Viewport.GetFirstPacketIndex();
const int32 StartSampleIndex = (StartPacketIndex - FirstPacketIndex) / PacketsPerSample;
const float X1 = FMath::Max(-2.0f, StartSampleIndex * SampleW);
const int32 EndSampleIndex = (EndPacketIndex - FirstPacketIndex) / PacketsPerSample;
const float X2 = FMath::Min(Viewport.GetWidth() + 2.0f, EndSampleIndex * SampleW);
const FAxisViewportDouble& ViewportY = Viewport.GetVerticalAxisViewport();
const float ViewHeight = FMath::RoundToFloat(Viewport.GetHeight());
const float Y = 0.0f;
const float H = ViewHeight - Y;
//// Animate color from white (if selected and hovered) or yellow (if only selected) to black, using a squared sine function.
// const double Time = static_cast<double>(FPlatformTime::Cycles64()) * FPlatformTime::GetSecondsPerCycle64();
// float S = FMath::Sin(2.0 * Time);
// S = S * S; // squared, to ensure only positive [0 - 1] values
// const FLinearColor Color(S, S, S, 1.0f);
//
//// Draw border around the selected box.
// DrawContext.DrawBox(X1 - 1.0f, Y - 1.0f, X2 - X1 + 2.0f, H + 2.0f, SelectedEventBorderBrush, Color);
// Fill the selected area.
const int32 PacketCount = EndPacketIndex - StartPacketIndex;
if (PacketCount > 1)
{
const float MinX = 0.0f;
const float MaxX = Viewport.GetWidth();
if (X1 <= MaxX && X2 >= MinX)
{
const FString Text = FString::Printf(TEXT("%d packets"), PacketCount);
FDrawHelpers::DrawSelection(DrawContext, MinX, MaxX, X1, X2, Y, H, 30.0f, Text, WhiteBrush, SelectionFont);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////