Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Public/DynamicRenderScaling.h
Guillaume Abadie bbb8d0e2c8 Rewrites dynamic resolution on top of the DynamicRenderScaling API
#rb none
#jira UE-152561
#preflight 628f43e6f622d972b5cb4f2f

[CL 20377247 by Guillaume Abadie in ue5-main branch]
2022-05-26 05:34:08 -04:00

231 lines
6.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Containers/List.h"
#include "HAL/IConsoleManager.h"
namespace DynamicRenderScaling
{
template<typename Type>
class TMap;
/* Model how the GPU costs of a budget scales with a ResolutionFraction. */
enum class EHeuristicModel
{
Unknown,
// GPU cost scales linearly to the ResolutionFraction
Linear,
// GPU cost scales quadratically to the ResolutionFraction
Quadratic,
};
/* Represent an independent budget to dynamically scale by its own. */
struct RENDERCORE_API FHeuristicSettings final
{
static constexpr float kDefaultMinResolutionFraction = 0.5f;
static constexpr float kDefaultMaxResolutionFraction = 1.0f;
static constexpr float kBudgetMsDisabled = 0.0f;
static constexpr float kDefaultChangeThreshold = 0.02f;
static constexpr float kDefaultTargetedHeadRoom = 0.05f;
static constexpr float kDefaultIncreaseAmortizationFactor = 0.9f;
static constexpr int32 kDefaultFractionQuantization = 0;
EHeuristicModel Model = EHeuristicModel::Unknown;
bool bModelScalesWithPrimaryScreenPercentage = false;
float MinResolutionFraction = kDefaultMinResolutionFraction;
float MaxResolutionFraction = kDefaultMaxResolutionFraction;
float BudgetMs = kBudgetMsDisabled;
float ChangeThreshold = kDefaultChangeThreshold;
float TargetedHeadRoom = kDefaultTargetedHeadRoom;
float IncreaseAmortizationFactor = kDefaultIncreaseAmortizationFactor;
int32 FractionQuantization = kDefaultFractionQuantization;
/** Returns whether the heuristic is enabled or not. */
bool IsEnabled() const;
/** Returns the desired GPU cost to be targeted to have head room left to not go over budget. */
float GetTargetedMs() const;
/** Returns how much the GPU cost scales for a given ResolutionFraction. */
float EstimateCostScale(float ResolutionFraction) const;
/** Returns how much the ResolutionFraction should scale for a GPU timing to fit to target. */
float EstimateResolutionFactor(float TimingMs) const;
/** Returns how much the GPU time should scale between two different resolution fraction. */
float EstimateTimeFactor(float CurrentResolutionFraction, float NewResolutionFraction) const;
/** Corrects new resolution fraction to ensure it's within bounds, honor AmortizationFactor and FractionQuantization. */
float CorrectNewResolutionFraction(float CurrentResolutionFraction, float NewResolutionFraction, float ResolutionFractionScale) const;
/** Returns whether the ResolutionFraction is changing meaningfully enough. */
bool DoesResolutionChangeEnough(float CurrentResolutionFraction, float NewResolutionFraction, bool bCanChangeResolution) const;
};
/* Represent an independent budget to dynamically scale by its own. */
class RENDERCORE_API FBudget final
{
public:
FBudget(const TCHAR* Name, FHeuristicSettings (*HeuristicSettingsGetter)(void));
~FBudget();
/* Returns the global list of all dynamic resolution budgets. */
static TLinkedList<FBudget*>*& GetGlobalList();
static int32 GetGlobalListSize();
inline const TCHAR* GetName() const
{
return Name;
}
inline const char* GetAnsiName() const
{
return AnsiName.GetData();
}
/* Returns the settings of the heuristic for this budget. */
inline const FHeuristicSettings& GetSettings() const
{
return CachedSettings;
}
inline int32 GetBudgetId() const
{
return BudgetId;
}
inline bool operator == (const FBudget& Other) const
{
return BudgetId == Other.BudgetId;
}
private:
const TCHAR* Name;
TArray<char> AnsiName;
FHeuristicSettings(*HeuristicSettingsGetter)(void);
TLinkedList<FBudget*> GlobalListLink;
FHeuristicSettings CachedSettings;
int32 BudgetId = 0;
UE_NONCOPYABLE(FBudget);
template<typename Type>
friend class TMap;
friend RENDERCORE_API void UpdateHeuristicsSettings();
};
/* Map of FBudget -> <Type>. */
template<typename Type>
class TMap final
{
public:
static constexpr int32 kInlineAllocatedBudgets = 16;
TMap()
{
Array.SetNum(FBudget::GetGlobalListSize());
#if !UE_BUILD_SHIPPING
for (TLinkedList<FBudget*>::TIterator BudgetIt(FBudget::GetGlobalList()); BudgetIt; BudgetIt.Next())
{
Array[BudgetIt->BudgetId].Name = BudgetIt->GetName();
}
#endif
}
TMap(const Type& Value)
: TMap()
{
SetAll(Value);
}
TMap(const TMap<Type>& Map) = default;
~TMap() = default;
inline void SetAll(const Type& Value)
{
Array.SetNum(FBudget::GetGlobalListSize());
for (int32 i = 0; i < Array.Num(); i++)
{
Array[i].Value = Value;
}
}
inline const Type& operator [](const FBudget& Budget) const
{
check(Array.Num() == FBudget::GetGlobalListSize());
return Array[Budget.BudgetId].Value;
}
inline Type& operator [](const FBudget& Budget)
{
check(Array.Num() == FBudget::GetGlobalListSize());
return Array[Budget.BudgetId].Value;
}
inline const Type& operator [](const int32 BudgetId) const
{
check(Array.Num() == FBudget::GetGlobalListSize());
return Array[BudgetId].Value;
}
inline Type& operator [](const int32 BudgetId)
{
check(Array.Num() == FBudget::GetGlobalListSize());
return Array[BudgetId].Value;
}
private:
struct FItem
{
#if !UE_BUILD_SHIPPING
const TCHAR* Name = nullptr;
#endif
Type Value;
};
TArray<FItem, TInlineAllocator<kInlineAllocatedBudgets>> Array;
};
constexpr float FractionToPercentage(float Fraction)
{
return Fraction * 100.0f;
}
constexpr float PercentageToFraction(float Percentage)
{
return Percentage / 100.0f;
}
inline float GetPercentageCVarToFraction(const TAutoConsoleVariable<float>& Percentage)
{
return PercentageToFraction(Percentage.GetValueOnAnyThread());
}
/** Returns whether the DynamicRenderScaling API is supported */
RENDERCORE_API bool IsSupported();
/** Updates all FBudget::GetSettings() with their new FHeuristicSettings. */
RENDERCORE_API void UpdateHeuristicsSettings();
/** Begins recording GPU timings in RDG for all the different FBudgets. */
RENDERCORE_API void BeginFrame(const TMap<bool>& bIsBudgetEnabled);
/** Ends recording GPU timings in RDG for all the different FBudgets. */
RENDERCORE_API void EndFrame();
/** Returns the latest available timings. */
RENDERCORE_API const TMap<uint64>& GetLastestTimings();
} // namespace DynamicRenderScaling