Files
UnrealEngine/Engine/Plugins/Media/PixelStreaming2/Source/PixelStreaming2RTC/Private/DebugGraph.cpp
2025-05-18 13:04:45 +08:00

165 lines
5.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DebugGraph.h"
#include "Engine/Canvas.h"
#include "Engine/Engine.h"
namespace UE::PixelStreaming2
{
FDebugGraph::FDebugGraph(FName InName, int InSamples, float InMinRange, float InMaxRange, float InRefValue)
: Name(InName)
, MaxSamples(InSamples)
, MinRange(InMinRange)
, MaxRange(InMaxRange)
, RefValue(InRefValue)
{
Values.SetNumZeroed(InSamples);
AvgValues.SetNumZeroed(InSamples);
}
FDebugGraph::FDebugGraph(const FDebugGraph& Other)
: Name(Other.Name)
, MaxSamples(Other.MaxSamples)
, MinRange(Other.MinRange)
, MaxRange(Other.MaxRange)
, RefValue(Other.RefValue)
, Sum(Other.Sum)
, Values(Other.Values)
, AvgValues(Other.AvgValues)
{
}
void FDebugGraph::AddValue(float InValue)
{
FScopeLock Lock(&CriticalSection);
if (bFirstValue)
{
// If it the first value, fill the graph with it
for (int i = 0; i < MaxSamples; i++)
{
AddValueInternal(InValue);
}
bFirstValue = false;
}
else
{
AddValueInternal(InValue);
}
}
void FDebugGraph::AddValueInternal(float InValue)
{
if (InValue > MaxRange)
{
// Increase max range by 50% larger than this new larger value
float NewMax = InValue * 2.0f;
float Multiplier = NewMax / MaxRange;
float Ratio = 1.0f / Multiplier;
MaxRange = NewMax;
// Increasing the max range means we must adjust all our existing values/averages/sum by the inverse
for (int i = 0; i < MaxSamples; i++)
{
Values[i] *= Ratio;
AvgValues[i] *= Ratio;
}
Sum *= Ratio;
}
InsertIndex = (InsertIndex + 1) % MaxSamples;
const float NormalizedValue = (InValue - MinRange) / (MaxRange - MinRange);
Sum -= Values[InsertIndex];
Sum += NormalizedValue;
Values[InsertIndex] = NormalizedValue;
AvgValues[InsertIndex] = Sum / BufferedValues;
BufferedValues = FGenericPlatformMath::Min(MaxSamples, BufferedValues + 1);
}
void FDebugGraph::Draw(FCanvas* Canvas, FVector2D Position, FVector2D Size) const
{
FScopeLock Lock(&CriticalSection);
FCanvasTileItem BgItem(Position, Size, FColor{ 0x10, 0x10, 0x10, 0xBB });
BgItem.BlendMode = SE_BLEND_Translucent;
BgItem.Draw(Canvas);
FVector2D StartPosition;
FVector2D AvgStartPosition;
float MinValue = TNumericLimits<float>::Max();
float MaxValue = TNumericLimits<float>::Min();
int ReadIndex = (InsertIndex + 1) % MaxSamples;
for (int i = 0; i < MaxSamples; ++i, ReadIndex = (ReadIndex + 1) % MaxSamples)
{
const float NormalizedValue = FMath::Clamp(Values[ReadIndex], 0.0f, 1.0f);
const float NormalizedAvgValue = FMath::Clamp(AvgValues[ReadIndex], 0.0f, 1.0f);
const float Unnormalized = NormalizedValue * (MaxRange - MinRange) + MinRange;
const float ValueBasis = i * Size.X / MaxSamples;
const float ValueOffset = Size.Y - NormalizedValue * Size.Y;
const float AvgValueOffset = Size.Y - NormalizedAvgValue * Size.Y;
const FVector2D EndPosition = Position + FVector2D{ ValueBasis, ValueOffset };
const FVector2D AvgEndPosition = Position + FVector2D{ ValueBasis, AvgValueOffset };
if (i > 0)
{
FCanvasLineItem Line(StartPosition, EndPosition);
Line.SetColor(FColor::White);
Line.Draw(Canvas);
FCanvasLineItem AvgLine(AvgStartPosition, AvgEndPosition);
AvgLine.SetColor(FColor::Blue);
AvgLine.Draw(Canvas);
}
StartPosition = EndPosition;
AvgStartPosition = AvgEndPosition;
MinValue = FGenericPlatformMath::Min(MinValue, Unnormalized);
MaxValue = FGenericPlatformMath::Max(MaxValue, Unnormalized);
}
// todo: should have a function to shrink the min/max range if min/max value is < 50% of range
FCanvasTextItem TextItem(Position, FText(), FSlateFontInfo(UEngine::GetTinyFont(), 9), FLinearColor(0, 1, 0));
TextItem.Text = FText::FromString(FString::Printf(TEXT("%s [%.2f, %.2f]"), *Name.ToString(), MinRange, MaxRange));
Canvas->DrawItem(TextItem);
const float Unnormalized = AvgValues[InsertIndex] * (MaxRange - MinRange) + MinRange;
TextItem.Text = FText::FromString(FString::Printf(TEXT("Avg: %.2f"), Unnormalized));
TextItem.Position.Y += TextItem.DrawnSize.Y;
Canvas->DrawItem(TextItem);
TextItem.Text = FText::FromString(FString::Printf(TEXT("Max: %.2f"), MaxValue));
TextItem.Position.Y += TextItem.DrawnSize.Y;
Canvas->DrawItem(TextItem);
TextItem.Text = FText::FromString(FString::Printf(TEXT("Min: %.2f"), MinValue));
TextItem.Position.Y += TextItem.DrawnSize.Y;
Canvas->DrawItem(TextItem);
if (RefValue != 0.0f)
{
const float NormalizedRefValue = FMath::Clamp((RefValue - MinRange) / (MaxRange - MinRange), 0.0f, 1.0f);
const float ValueOffset = NormalizedRefValue * Size.Y;
const FVector2D StartRefPosition{ Position.X, Position.Y + Size.Y - ValueOffset };
const FVector2D EndRefPosition{ Position.X + Size.X, Position.Y + Size.Y - ValueOffset };
FCanvasLineItem RefLine(StartRefPosition, EndRefPosition);
RefLine.SetColor(FColor::Red);
RefLine.Draw(Canvas);
TextItem.Text = FText::FromString(FString::Printf(TEXT("Ref: %.2f"), RefValue));
TextItem.Position.Y += TextItem.DrawnSize.Y;
Canvas->DrawItem(TextItem);
}
}
} // namespace UE::PixelStreaming2