Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions GeneralsMD/Code/GameEngine/Include/Common/GameLOD.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ class GameLODManager
Bool isReallyLowMHz() const { return m_cpuFreq < m_reallyLowMHz; }
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
void updateGraphicsQualityState(float averageFPS);
void restoreQualitySettings();
bool getFrameSkipEnabled() const { return m_frameSkipEnabled; }
bool isQualityReduced() const { return m_isQualityReduced; }
#endif

StaticGameLODInfo m_staticGameLODInfo[STATIC_GAME_LOD_COUNT];
Expand Down Expand Up @@ -230,14 +233,14 @@ class GameLODManager
Real m_compositeBenchIndex;
Int m_reallyLowMHz;
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
bool m_userGraphSnapshotTaken;
bool m_userShadowVolumesEnabled;
bool m_userShadowDecalsEnabled;
bool m_userHeatEffectsEnabled;
bool m_isQualityReduced;
int m_stableFPSDuration;
int m_lowFPSSecondsCount;
DynamicGameLODLevel m_userDynamicLOD;
bool m_frameSkipEnabled;
int m_stableFPSSecondsCount;
int m_lowFPSSecondsCount;
int m_userMaxParticleCount;
#endif
};

Expand Down
102 changes: 52 additions & 50 deletions GeneralsMD/Code/GameEngine/Source/Common/GameLOD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include "Common/GameLOD.h"
#include "GameClient/TerrainVisual.h"
#include "GameClient/GameClient.h"
#include "GameClient/Shell.h"
#include "GameLogic/GameLogic.h"
#include "Common/UserPreferences.h"

#define DEFINE_PARTICLE_SYSTEM_NAMES
Expand Down Expand Up @@ -232,14 +232,11 @@ GameLODManager::GameLODManager(void)
m_numBenchProfiles=0;
m_reallyLowMHz = 400;
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
m_userGraphSnapshotTaken = false;
m_userShadowVolumesEnabled = true;
m_userShadowDecalsEnabled = true;
m_userHeatEffectsEnabled = true;
m_isQualityReduced = false;
m_stableFPSDuration = 0;
m_frameSkipEnabled = false;
m_stableFPSSecondsCount = 0;
m_lowFPSSecondsCount = 0;
m_userDynamicLOD = DYNAMIC_GAME_LOD_VERY_HIGH;
m_userMaxParticleCount = 0;
#endif

for (Int i=0; i<STATIC_GAME_LOD_CUSTOM; i++)
Expand Down Expand Up @@ -782,50 +779,41 @@ Bool GameLODManager::didMemPass( void )
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
void GameLODManager::updateGraphicsQualityState(float averageFPS)
{
if (!m_userGraphSnapshotTaken)
{
m_userShadowVolumesEnabled = TheGlobalData->m_useShadowVolumes;
m_userShadowDecalsEnabled = TheGlobalData->m_useShadowDecals;
m_userHeatEffectsEnabled = TheGlobalData->m_useHeatEffects;
m_userDynamicLOD = m_currentDynamicLOD;
m_userGraphSnapshotTaken = true;
}
if (!TheGameLogic || (TheGameLogic->getFrame() % LOGICFRAMES_PER_SECOND) != 0)
return;

if (m_isQualityReduced && TheGameClient && TheGameClient->getFrame() <= 1)
if (TheGameLogic->isInShellGame() || TheGameLogic->isInReplayGame() || (TheGameLogic->getFrame() < LOGICFRAMES_PER_SECOND))
{
TheWritableGlobalData->m_useShadowVolumes = m_userShadowVolumesEnabled;
TheWritableGlobalData->m_useShadowDecals = m_userShadowDecalsEnabled;
TheWritableGlobalData->m_useHeatEffects = m_userHeatEffectsEnabled;
setDynamicLODLevel(m_userDynamicLOD);
if (TheGameClient)
TheGameClient->allocateShadows();
m_isQualityReduced = false;
m_stableFPSDuration = 0;
if (m_isQualityReduced || m_frameSkipEnabled)
restoreQualitySettings();
return;
}

if (!m_isQualityReduced)
{
m_userShadowVolumesEnabled = TheGlobalData->m_useShadowVolumes;
m_userShadowDecalsEnabled = TheGlobalData->m_useShadowDecals;
m_userHeatEffectsEnabled = TheGlobalData->m_useHeatEffects;
m_userDynamicLOD = m_currentDynamicLOD;
m_userMaxParticleCount = TheGlobalData->m_maxParticleCount;
}

if (averageFPS < 56.0f)
m_lowFPSSecondsCount++, m_stableFPSDuration = 0;
else if (averageFPS > 57.0f)
m_stableFPSDuration++, m_lowFPSSecondsCount = 0;
// Track how many consecutive seconds FPS is below or above threshold.
const float MIN_ACCEPTABLE_FPS = 58.f;
averageFPS < MIN_ACCEPTABLE_FPS ? (m_lowFPSSecondsCount++, m_stableFPSSecondsCount = 0)
: (m_stableFPSSecondsCount++, m_lowFPSSecondsCount = 0);

bool shouldReduceQuality = (m_lowFPSSecondsCount >= 2 && TheGameClient && TheGameClient->getFrame() > LOGICFRAMES_PER_SECOND * 10 && !TheShell->isShellActive());
if (shouldReduceQuality && !m_isQualityReduced)
bool isInGame = TheGameLogic->isInGame();
if (isInGame)
{
if (averageFPS < 56.0f)
m_dynamicGameLODInfo[DYNAMIC_GAME_LOD_LOW].m_minDynamicParticlePriority = WEAPON_TRAIL;
if (averageFPS < 40.0f)
m_dynamicGameLODInfo[DYNAMIC_GAME_LOD_LOW].m_minDynamicParticlePriority = ALWAYS_RENDER;
if (averageFPS < MIN_ACCEPTABLE_FPS && m_lowFPSSecondsCount >= 1)
m_frameSkipEnabled = true;
else if (averageFPS >= MIN_ACCEPTABLE_FPS && m_stableFPSSecondsCount >= 1)
m_frameSkipEnabled = false;
}


setDynamicLODLevel(DYNAMIC_GAME_LOD_LOW);
bool shouldReduceQuality = (m_lowFPSSecondsCount >= 2 && isInGame);
if (shouldReduceQuality && !m_isQualityReduced)
{
TheGameClient->releaseShadows();
TheWritableGlobalData->m_useShadowVolumes = false;
TheWritableGlobalData->m_useShadowDecals = false;
Expand All @@ -834,24 +822,38 @@ void GameLODManager::updateGraphicsQualityState(float averageFPS)
m_lowFPSSecondsCount = 0;
}

// Restore to user preferences after sustained good performance
else if (!shouldReduceQuality && m_isQualityReduced)
if (m_isQualityReduced)
{
if (m_stableFPSDuration > 15)
{
TheWritableGlobalData->m_useShadowVolumes = m_userShadowVolumesEnabled;
TheWritableGlobalData->m_useShadowDecals = m_userShadowDecalsEnabled;
TheWritableGlobalData->m_useHeatEffects = m_userHeatEffectsEnabled;
float particleReductionFactor = max(0.f, min(1.f, (MIN_ACCEPTABLE_FPS - averageFPS) / MIN_ACCEPTABLE_FPS * 5.f));
int targetCount = max(100, (int)(m_userMaxParticleCount * (1.f - particleReductionFactor)));
int current = TheGlobalData->m_maxParticleCount;

if (TheGameClient)
TheGameClient->allocateShadows();
if (targetCount < current)
TheWritableGlobalData->m_maxParticleCount = max(100, current + (int)((targetCount - current) * 0.5f));

DynamicGameLODLevel lod = TheGameLODManager->findDynamicLODLevel(averageFPS);
TheGameLODManager->setDynamicLODLevel(lod);
if (!shouldReduceQuality && m_stableFPSSecondsCount > 15)
{
int newCount = current + (int)((m_userMaxParticleCount - current) * 0.3f);

m_isQualityReduced = false;
m_stableFPSDuration = 0;
if (newCount >= m_userMaxParticleCount || newCount == current)
restoreQualitySettings();
else
TheWritableGlobalData->m_maxParticleCount = newCount;
}
}
}

void GameLODManager::restoreQualitySettings()
{
TheWritableGlobalData->m_useShadowVolumes = m_userShadowVolumesEnabled;
TheWritableGlobalData->m_useShadowDecals = m_userShadowDecalsEnabled;
TheWritableGlobalData->m_useHeatEffects = m_userHeatEffectsEnabled;
TheWritableGlobalData->m_maxParticleCount = m_userMaxParticleCount;
m_stableFPSSecondsCount = 0;
m_lowFPSSecondsCount = 0;
m_frameSkipEnabled = false;
m_isQualityReduced = false;
if (TheGameClient)
TheGameClient->allocateShadows();
}
#endif // GENERALS_ONLINE_HIGH_FPS_SERVER
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ class W3DDisplay : public Display
Bool m_isClippedEnabled; ///<used by 2D drawing operations to define clip re
Real m_averageFPS; ///<average fps over the last 30 frames.
Real m_currentFPS; ///<current fps value.
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
float m_frameSkipAccumulator = 0.0f;
#endif

#if defined(RTS_DEBUG)
Int64 m_timerAtCumuFPSStart;
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1687,8 +1687,17 @@ void W3DDisplay::draw( void )

updateAverageFPS();
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
if (TheGameLogic && (TheGameLogic->getFrame() % LOGICFRAMES_PER_SECOND) == 0)
TheGameLODManager->updateGraphicsQualityState(m_averageFPS);
TheGameLODManager->updateGraphicsQualityState(m_averageFPS);
if (TheGameLODManager->getFrameSkipEnabled()) {
float skipRatio = min(0.5f, max(0.0f, ((float)LOGICFRAMES_PER_SECOND - m_averageFPS) / (float)LOGICFRAMES_PER_SECOND * 2.0f));
m_frameSkipAccumulator += skipRatio;
if (m_frameSkipAccumulator >= 1.0f) {
m_frameSkipAccumulator -= 1.0f;
WW3D::SkipNextRenderFrame = true;
}
}
else
m_frameSkipAccumulator = 0.0f;
#else
if (TheGlobalData->m_enableDynamicLOD && TheGameLogic->getShowDynamicLOD())
{
Expand Down Expand Up @@ -2073,6 +2082,10 @@ void W3DDisplay::createLightPulse( const Coord3D *pos, const RGBColor *color,
if (innerRadius+attenuationWidth<2.0*PATHFIND_CELL_SIZE_F + 1.0f) {
return; // it basically won't make any visual difference. jba.
}
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
if (TheGameLODManager && TheGameLODManager->isQualityReduced())
return;
#endif
W3DDynamicLight * theDynamicLight = m_3DScene->getADynamicLight();
// turn it on.
theDynamicLight->setEnabled(true);
Expand Down
11 changes: 11 additions & 0 deletions GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
**
***********************************************************************************/

float WW3D::LogicFrameTimeMs = 1000.0f / WWSyncPerSecond; // initialized to something to avoid division by zero on first use

Check warning on line 166 in GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp

View workflow job for this annotation

GitHub Actions / Build GeneralsMD / win32+e

operator '/': deprecated between enumerations and floating-point types

Check warning on line 166 in GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp

View workflow job for this annotation

GitHub Actions / Build GeneralsMD / win32-profile+e

operator '/': deprecated between enumerations and floating-point types

Check warning on line 166 in GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp

View workflow job for this annotation

GitHub Actions / Build GeneralsMD / win32-debug+e

operator '/': deprecated between enumerations and floating-point types
float WW3D::FractionalSyncMs = 0.0f;
unsigned int WW3D::SyncTime = 0;
unsigned int WW3D::PreviousSyncTime = 0;
Expand All @@ -175,6 +175,9 @@

bool WW3D::IsInitted = false;
bool WW3D::IsRendering = false;
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
bool WW3D::SkipNextRenderFrame = false;
#endif
bool WW3D::IsCapturing = false;
bool WW3D::IsScreenUVBiased = false;

Expand Down Expand Up @@ -852,6 +855,14 @@
DX8Wrapper::Clear(clear, clearz, color, dest_alpha);
}

#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
if (WW3D::SkipNextRenderFrame) {
WW3D::SkipNextRenderFrame = false;
IsRendering = false;
return WW3D_ERROR_GENERIC;
}
#endif

// Notify D3D that we are beginning to render the frame
DX8Wrapper::Begin_Scene();

Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ class WW3D

// Gamma control
static void Set_Gamma(float gamma,float bright,float contrast,bool calibrate=true);
#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER)
static bool SkipNextRenderFrame;
#endif

private:

Expand Down
Loading