You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/CrySystem/OverloadSceneManager/OverloadSceneManager.cpp

291 lines
11 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Manages overload values (eg CPU,GPU etc)
// 1.0="everything is ok" 0.0="very bad frame rate"
// various systems can use this information and control what is currently in the scene
#include "CrySystem_precompiled.h"
#include "OverloadSceneManager.h"
//--------------------------------------------------------------------------------------------------
// Name: COverloadSceneManager
// Desc: Constructor
//--------------------------------------------------------------------------------------------------
COverloadSceneManager::COverloadSceneManager()
{
InitialiseCVars();
m_currentFrameStat = 0;
ResetDefaultValues();
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Desc: static console callback functions
//--------------------------------------------------------------------------------------------------
static void OnChange_osm_enabled(ICVar* pCVar)
{
if (pCVar->GetIVal() == 0)
{
gEnv->pOverloadSceneManager->Reset();
//gEnv->pRenderer->EnablePipelineProfiler(false); // would need push/pop since something else might have enabled it
}
else if (pCVar->GetIVal() == 1)
{
gEnv->pRenderer->EnablePipelineProfiler(true);
}
}
static void cmd_setFBScale(IConsoleCmdArgs* pParams)
{
int argCount = pParams->GetArgCount();
Vec2 newScale = Vec2(0.0f, 0.0f);
gEnv->pRenderer->EF_Query(EFQ_GetViewportDownscaleFactor, newScale);
if (argCount > 1)
{
newScale.x = clamp_tpl((float)atof(pParams->GetArg(1)), 0.0f, 1.0f);
if (argCount > 2)
{
newScale.y = clamp_tpl((float)atof(pParams->GetArg(2)), 0.0f, 1.0f);
}
else
{
newScale.y = newScale.x;
}
newScale = gEnv->pRenderer->SetViewportDownscale(newScale.x, newScale.y);
}
int nWidth = gEnv->pRenderer->GetWidth();
int nHeight = gEnv->pRenderer->GetHeight();
gEnv->pLog->LogWithType(ILog::eInputResponse, "Current Viewport Resolution: %dx%d",
int(nWidth * newScale.x), int(nHeight * newScale.y));
}
//--------------------------------------------------------------------------------------------------
// Name: InitialiseCVars
// Desc: Initialises CVars
//--------------------------------------------------------------------------------------------------
void COverloadSceneManager::InitialiseCVars()
{
// depending on final requirements, these could be made into const cvars
REGISTER_CVAR_CB(osm_enabled, 0, VF_NULL, "Enables/disables overload scene manager", &OnChange_osm_enabled);
REGISTER_CVAR(osm_historyLength, 5, VF_NULL, "Overload scene manager number of frames to record stats for");
REGISTER_CVAR(osm_targetFPS, 28.0f, VF_NULL, "Overload scene manager target frame rate");
REGISTER_CVAR(osm_targetFPSTolerance, 1.0f, VF_NULL, "The overload scene manager will make adjustments if fps is outside targetFPS +/- this value");
REGISTER_CVAR(osm_fbScaleDeltaDown, 5.0f, VF_NULL, "The speed multiplier for the overload scene manager frame buffer scaling down");
REGISTER_CVAR(osm_fbScaleDeltaUp, 1.0f, VF_NULL, "The speed multiplier for the overload scene manager frame buffer scaling up");
REGISTER_CVAR(osm_fbMinScale, 0.66f, VF_NULL, "The minimum scale factor the overload scene manager will drop to");
REGISTER_COMMAND("osm_setFBScale", cmd_setFBScale, VF_NULL, "Sets the framebuffer scale to either a single scale on both X and Y, or independent scales.\n"
"NOTE: Will be overridden immediately if Overload scene manager is still enabled - see osm_enabled");
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Reset
// Desc: Resets overload scene manager outputs to sensible defaults
//--------------------------------------------------------------------------------------------------
void COverloadSceneManager::Reset()
{
ResetDefaultValues();
gEnv->pRenderer->SetViewportDownscale(m_fbScale, m_fbScale);
}
void COverloadSceneManager::ResetDefaultValues()
{
m_fbScale = 1.0f;
m_scaleState = FBSCALE_AUTO;
m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f;
m_lerpOverride.m_reversed = false;
m_lerpAuto.m_start = m_lerpAuto.m_length = 1.0f;
m_lerpAuto.m_reversed = true;
m_fbAutoScale = m_fbOverrideDestScale = m_fbOverrideCurScale = 1.0f;
// completely reset history
for (int i = 0; i < osm_historyLength; i++)
{
SScenePerformanceStats& stats = m_sceneStats[i];
stats.frameRate = stats.gpuFrameRate = osm_targetFPS;
}
m_smoothedSceneStats.frameRate = m_smoothedSceneStats.gpuFrameRate = osm_targetFPS;
}
//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Update
// Desc: Updates overload scene manager
//--------------------------------------------------------------------------------------------------
void COverloadSceneManager::Update()
{
if (!osm_enabled)
{
return;
}
UpdateStats();
ResizeFB();
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: OverrideScale and ResetScale
// Desc: sets up appropriate members for lerping between automatic framebuffer scale and manual
// overrides.
//--------------------------------------------------------------------------------------------------
void COverloadSceneManager::OverrideScale(float frameScale, float dt)
{
dt = max(dt, 1.0f / 1000.0f);
float curTime = gEnv->pTimer->GetCurrTime();
frameScale = clamp_tpl(frameScale, osm_fbMinScale, 1.0f);
m_fbOverrideDestScale = frameScale;
if (m_scaleState == FBSCALE_AUTO)
{
// remove any override lerp - we want to lerp straight from auto to the given value.
m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f;
m_lerpOverride.m_reversed = false;
m_fbOverrideCurScale = frameScale;
m_lerpAuto.m_start = curTime;
m_lerpAuto.m_length = dt;
m_lerpAuto.m_reversed = false;
}
else if (m_scaleState == FBSCALE_OVERRIDE)
{
m_lerpOverride.m_start = curTime;
m_lerpOverride.m_length = dt;
m_lerpOverride.m_reversed = false;
m_fbOverrideCurScale = m_fbScale;
}
m_scaleState = FBSCALE_OVERRIDE;
}
void COverloadSceneManager::ResetScale(float dt)
{
dt = max(dt, 1.0f / 1000.0f);
float curTime = gEnv->pTimer->GetCurrTime();
// remove any override lerp - we want to lerp straight to auto
m_lerpOverride.m_start = m_lerpOverride.m_length = 1.0f;
m_lerpOverride.m_reversed = false;
m_fbOverrideCurScale = m_fbOverrideDestScale = m_fbScale;
m_lerpAuto.m_start = curTime;
m_lerpAuto.m_length = dt;
m_lerpAuto.m_reversed = true; // want to lerp back to auto mode
m_scaleState = FBSCALE_AUTO;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: UpdateStats
// Desc: Updates overload stats
//--------------------------------------------------------------------------------------------------
void COverloadSceneManager::UpdateStats()
{
m_currentFrameStat++;
if (m_currentFrameStat >= osm_historyLength)
{
m_currentFrameStat = 0;
}
SScenePerformanceStats& currentStats = m_sceneStats[m_currentFrameStat];
const float frameLength = gEnv->pTimer->GetRealFrameTime() * 1000.0f;
const float gpuFrameLength = gEnv->pRenderer->GetGPUFrameTime() * 1000.0f;
currentStats.frameRate = frameLength > 0.0f ? 1000.0f / frameLength : 0.0f;
currentStats.gpuFrameRate = gpuFrameLength > 0.0f ? 1000.0f / gpuFrameLength : 0.0f;
CalculateSmoothedStats();
}//-------------------------------------------------------------------------------------------------
void COverloadSceneManager::CalculateSmoothedStats()
{
m_smoothedSceneStats.Reset();
for (int i = 0; i < osm_historyLength; i++)
{
SScenePerformanceStats& stats = m_sceneStats[i];
m_smoothedSceneStats.frameRate += stats.frameRate;
m_smoothedSceneStats.gpuFrameRate += stats.gpuFrameRate;
}
m_smoothedSceneStats.frameRate /= osm_historyLength;
m_smoothedSceneStats.gpuFrameRate /= osm_historyLength;
}
float COverloadSceneManager::CalcFBScale()
{
float curTime = gEnv->pTimer->GetCurrTime();
// first calculate delta of the override lerp
float delta = clamp_tpl((curTime - m_lerpOverride.m_start) / m_lerpOverride.m_length, 0.0f, 1.0f);
if (m_lerpOverride.m_reversed)
{
delta = 1.0f - delta;
}
// get the current target override
float curOverrideScale = LERP(m_fbOverrideCurScale, m_fbOverrideDestScale, delta);
// calculate the delta from (or two) automatic scaling
delta = clamp_tpl((curTime - m_lerpAuto.m_start) / m_lerpAuto.m_length, 0.0f, 1.0f);
if (m_lerpAuto.m_reversed)
{
delta = 1.0f - delta;
}
// final lerp from automatic to current override
return LERP(m_fbAutoScale, curOverrideScale, delta);
}
void COverloadSceneManager::ResizeFB()
{
// don't do anything for invalid framerates
if (m_smoothedSceneStats.gpuFrameRate < 5.0f || m_smoothedSceneStats.gpuFrameRate > 100.0f)
{
return;
}
float fpsDiff = fabsf(m_smoothedSceneStats.gpuFrameRate - osm_targetFPS);
if (m_smoothedSceneStats.gpuFrameRate < osm_targetFPS - osm_targetFPSTolerance)
{
m_fbAutoScale -= osm_fbScaleDeltaDown / 1000.0f * fpsDiff;
}
else if (m_smoothedSceneStats.gpuFrameRate > osm_targetFPS + osm_targetFPSTolerance)
{
m_fbAutoScale += osm_fbScaleDeltaUp / 1000.0f * fpsDiff;
}
m_fbAutoScale = clamp_tpl(m_fbAutoScale, osm_fbMinScale, 1.0f);
m_fbScale = clamp_tpl(CalcFBScale(), osm_fbMinScale, 1.0f);
gEnv->pRenderer->SetViewportDownscale(m_fbScale, m_fbScale);
}