From 32bbc175b39421fb3013cdd13fe20b3ec5f086d6 Mon Sep 17 00:00:00 2001
From: Adrian Courreges <a.courreges@gmail.com>
Date: Sat, 1 Dec 2018 10:05:17 +0900
Subject: [PATCH] Dynamic-resolution, adapt the rendering resolution depending
on the GPU time.
Enable with "r.DynamicResolution.Quality 1".
Full details and information: http://www.adriancourreges.com/blog/2018/12/02/ue4-optimized-post-effects/
---
Engine/Source/Runtime/Engine/Private/SceneView.cpp | 90 +++++++++++++++++++++-
.../Private/PostProcess/SceneRenderTargets.cpp | 6 +-
2 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/Engine/Source/Runtime/Engine/Private/SceneView.cpp b/Engine/Source/Runtime/Engine/Private/SceneView.cpp
index e0a29468283..7e159715703 100644
--- a/Engine/Source/Runtime/Engine/Private/SceneView.cpp
+++ b/Engine/Source/Runtime/Engine/Private/SceneView.cpp
@@ -324,6 +324,41 @@ static TAutoConsoleVariable<int32> CVarAllowTranslucencyAfterDOF(
ECVF_RenderThreadSafe);
+static TAutoConsoleVariable<int> CVarDynamicResolutionQuality(
+ TEXT("r.DynamicResolution.Quality"),
+ 0,
+ TEXT("Enable dynamic resolution which will override r.ScreenPercentage and modify it automatically at runtime to fit into some frame time budget.\n")
+ TEXT("For better result this should be used in combination with 'r.SceneRenderTargetResizeMethod 2'."),
+ ECVF_Scalability | ECVF_Default);
+
+static TAutoConsoleVariable<float> CVarDynamicResolutionMaxScreenPercentage(
+ TEXT("r.DynamicResolution.MaxScreenPercentage"),
+ 100.0f,
+ TEXT("Maximum screen percentage we allow the renderer to use when the scene is light."),
+ ECVF_Scalability | ECVF_Default);
+
+static TAutoConsoleVariable<float> CVarDynamicResolutionMinScreenPercentage(
+ TEXT("r.DynamicResolution.MinScreenPercentage"),
+ 80.0f,
+ TEXT("Minimum screen percentage we allow the renderer to fall down to when the scene gets very heavy."),
+ ECVF_Scalability | ECVF_Default);
+
+static TAutoConsoleVariable<float> CVarDynamicResolutionMaxTimeBudget(
+ TEXT("r.DynamicResolution.MaxTimeBudget"),
+ 29.0f,
+ TEXT("When rendering time exceeds MaxTimeBudget, we switch to a lower resolution to reduce burden on the GPU.\n")
+ TEXT("Defined in ms. It's better to be conservative: for a 60FPS budget, 14 or 15 values are better than 16 to avoid frame drops."),
+ ECVF_Scalability | ECVF_Default);
+
+static TAutoConsoleVariable<float> CVarDynamicResolutionMinTimeBudget(
+ TEXT("r.DynamicResolution.MinTimeBudget"),
+ 20.0f,
+ TEXT("When rendering time is lower than MinTimeBudget, we're very fast and we switch to higher resolution, increasing quality and GPU load.\n")
+ TEXT("Defined in ms. The value should be much lower than MaxTimeBudget to avoid some bouncing back and forth between HD and LD.\n")
+ TEXT("It's better to be conservative and have a value low enough you can be sure the increase in resolution won't violate the frame time budget, ")
+ TEXT("the ideal value can vary a lot depending on the difference between MaxScreenPercentage and MinScreenPercentage."),
+ ECVF_Scalability | ECVF_Default);
+
/** Global vertex color view mode setting when SHOW_VertexColors show flag is set */
EVertexColorViewMode::Type GVertexColorViewMode = EVertexColorViewMode::Color;
@@ -1823,7 +1858,60 @@ void FSceneView::EndFinalPostprocessSettings(const FSceneViewInitOptions& ViewIn
#endif
{
static const auto ScreenPercentageCVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.ScreenPercentage"));
- FinalPostProcessSettings.ScreenPercentage *= ScreenPercentageCVar->GetValueOnGameThread() / 100.0f;
+
+ if (CVarDynamicResolutionQuality.GetValueOnGameThread() > 0)
+ {
+ //
+ // Dynamic-resolution path. You can customize the logic here!
+ //
+ // We just bounce between 2 pre-defined ScreenPercentage values with a cool-down period
+ // but you can change this with your own logic, have more transitions, tune transition speed...
+ //
+
+ float Value = ScreenPercentageCVar->GetValueOnGameThread();
+
+ static int NoTouchFrames = 0; // won't change resolution while this is not 0
+ static int HighRes = 1;
+
+ if (NoTouchFrames > 0)
+ {
+ // We changed resolution recently, cool-down period
+ NoTouchFrames--;
+ }
+ else
+ {
+ // We'are allowed to change res
+
+ // GPU time. Not necessarily for the last frame, it can be 3 frames old to avoid readback stalls.
+ float frameTime = FPlatformTime::ToMilliseconds(GGPUFrameTime);
+
+ // Are we struggling at high resolution?
+ if (HighRes && (frameTime > CVarDynamicResolutionMaxTimeBudget.GetValueOnGameThread()) && (frameTime < 60.0f))
+ {
+ // Go to low-res and don't scale-up for a while
+ HighRes = 0;
+ NoTouchFrames = 50;
+ }
+ // Or do we have room to bump the resolution when we're very fast?
+ else if (!HighRes && (frameTime > 0.0f) && (frameTime < CVarDynamicResolutionMinTimeBudget.GetValueOnGameThread()))
+ {
+ // Go to high-res but check shortly after if we need to go back to low-res
+ HighRes = 1;
+ NoTouchFrames = 5;
+ }
+ }
+ Value *= ((HighRes ? CVarDynamicResolutionMaxScreenPercentage : CVarDynamicResolutionMinScreenPercentage).GetValueOnGameThread() / 100.0f);
+
+ // Apply the custom percentage to the scene
+ if (Value >= 0.0)
+ {
+ FinalPostProcessSettings.ScreenPercentage *= Value / 100.0f;
+ }
+ }
+ else
+ {
+ FinalPostProcessSettings.ScreenPercentage *= ScreenPercentageCVar->GetValueOnGameThread() / 100.0f;
+ }
}
#if WITH_EDITOR
diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp
index 58b137e6cca..360d81c4aa3 100644
--- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp
+++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp
@@ -299,7 +299,11 @@ FIntPoint FSceneRenderTargets::ComputeDesiredSize(const FSceneViewFamily& ViewFa
if(!FPlatformProperties::SupportsWindowedMode())
{
// Force ScreenRes on non windowed platforms.
- SceneTargetsSizingMethod = RequestedSize;
+ #if 1 // always grow to avoid RT re-allocation
+ SceneTargetsSizingMethod = Grow;
+ #else
+ SceneTargetsSizingMethod = RequestedSize;
+ #endif
}
else if (GIsEditor && !bIsVRScene)
{
--
2.14.1.windows.1