From d61a796d69045ca564dc7665ab73813d54e71a26 Mon Sep 17 00:00:00 2001 From: MrS-ibra Date: Tue, 31 Mar 2026 15:18:20 +0300 Subject: [PATCH] bugfix(gamelod): Restore adaptive FPS effects scaling after merge and disable light pulses when active --- .../Code/GameEngine/Include/Common/GameLOD.h | 9 +- .../Code/GameEngine/Source/Common/GameLOD.cpp | 101 +++++++++--------- .../W3DDevice/GameClient/W3DDisplay.cpp | 11 +- 3 files changed, 67 insertions(+), 54 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameLOD.h b/GeneralsMD/Code/GameEngine/Include/Common/GameLOD.h index e1097aaaaf..d97558e6a1 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GameLOD.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GameLOD.h @@ -190,6 +190,8 @@ class GameLODManager Bool isReallyLowMHz() const { return m_cpuFreq < m_reallyLowMHz; } #if defined(GENERALS_ONLINE_HIGH_FPS_SERVER) void updateGraphicsQualityState(float averageFPS); + void restoreQualitySettings(); + bool isQualityReduced() const { return m_isQualityReduced; } #endif StaticGameLODInfo m_staticGameLODInfo[STATIC_GAME_LOD_COUNT]; @@ -230,14 +232,13 @@ 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; + int m_stableFPSSecondsCount; + int m_lowFPSSecondsCount; + int m_userMaxParticleCount; #endif }; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameLOD.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameLOD.cpp index b17e8c4fba..07942300b2 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameLOD.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameLOD.cpp @@ -40,7 +40,7 @@ #define DEFINE_PARTICLE_SYSTEM_NAMES #include "GameClient/ParticleSys.h" -#include "GameClient/Shell.h" +#include "GameLogic/GameLogic.h" #define PROFILE_ERROR_LIMIT 0.94f //fraction of profiled result needed to get a match. Allows some room for error/fluctuation. @@ -232,14 +232,10 @@ GameLODManager::GameLODManager() 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_lowFPSSecondsCount = 0; - m_userDynamicLOD = DYNAMIC_GAME_LOD_VERY_HIGH; + m_stableFPSSecondsCount = 0; + m_userMaxParticleCount = 0; #endif for (Int i=0; im_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) + restoreQualitySettings(); + return; } if (!m_isQualityReduced) @@ -808,24 +793,26 @@ void GameLODManager::updateGraphicsQualityState(float averageFPS) 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 minAcceptedFPS = 58.f; + if (averageFPS < minAcceptedFPS) + { + m_lowFPSSecondsCount++; + m_stableFPSSecondsCount = 0; + } + else + { + m_stableFPSSecondsCount++; + m_lowFPSSecondsCount = 0; + } - bool shouldReduceQuality = (m_lowFPSSecondsCount >= 2 && TheGameClient && TheGameClient->getFrame() > LOGICFRAMES_PER_SECOND * 10 && !TheShell->isShellActive()); + bool isInGame = TheGameLogic->isInGame(); + bool shouldReduceQuality = (m_lowFPSSecondsCount >= 2 && isInGame); if (shouldReduceQuality && !m_isQualityReduced) { - 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; - - - setDynamicLODLevel(DYNAMIC_GAME_LOD_LOW); TheGameClient->releaseShadows(); TheWritableGlobalData->m_useShadowVolumes = false; TheWritableGlobalData->m_useShadowDecals = false; @@ -834,24 +821,40 @@ 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, (minAcceptedFPS - averageFPS) / minAcceptedFPS * 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)); + + if (!shouldReduceQuality && m_stableFPSSecondsCount > 15) + { + int newCount = current + (int)((m_userMaxParticleCount - current) * 0.3f); + if (newCount >= m_userMaxParticleCount || newCount == current) + restoreQualitySettings(); + else + TheWritableGlobalData->m_maxParticleCount = newCount; DynamicGameLODLevel lod = TheGameLODManager->findDynamicLODLevel(averageFPS); TheGameLODManager->setDynamicLODLevel(lod); - - m_isQualityReduced = false; - m_stableFPSDuration = 0; } } } + +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_isQualityReduced = false; + if (TheGameClient) + TheGameClient->allocateShadows(); +} #endif // GENERALS_ONLINE_HIGH_FPS_SERVER diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 7c1a34ab44..b6a293713a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1681,6 +1681,10 @@ void W3DDisplay::draw() return; updateAverageFPS(); + +#if defined(GENERALS_ONLINE_HIGH_FPS_SERVER) + TheGameLODManager->updateGraphicsQualityState(m_averageFPS); +#else if (TheGlobalData->m_enableDynamicLOD && TheGameLogic->getShowDynamicLOD()) { DynamicGameLODLevel lod = TheGameLODManager->findDynamicLODLevel(m_averageFPS); @@ -1690,7 +1694,7 @@ void W3DDisplay::draw() { //if dynamic LOD is turned off, force highest LOD TheGameLODManager->setDynamicLODLevel(DYNAMIC_GAME_LOD_VERY_HIGH); } - +#endif if (TheGlobalData->m_terrainLOD == TERRAIN_LOD_AUTOMATIC && TheTerrainRenderObject) { calculateTerrainLOD(); @@ -2060,6 +2064,11 @@ 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);