1
0
forked from 0ad/0ad

Optional FPS Limiter for running games too, use the Slider GUI object in the config to specify custom limits.

Make it way more accurate by excluding the SDL_Wait time and microsecond
precision.

Differential Revision: https://code.wildfiregames.com/D109
Refs #2882
Reviewed By: Vladislav
This was SVN commit r19507.
This commit is contained in:
elexis 2017-05-03 23:44:13 +00:00
parent dd9b83626e
commit 4a5f302ce1
4 changed files with 48 additions and 26 deletions

View File

@ -125,6 +125,9 @@ forcealphatest = false
; Color of the sky (in "r g b" format)
skycolor = "0 0 0"
[adaptivefps]
session = 60 ; Throttle FPS in running games (prevents 100% CPU workload).
menu = 30 ; Throttle FPS in menus only.
[hotkey]
; Each one of the specified keys will trigger the action on the left
@ -329,9 +332,6 @@ scale = 1.0 ; GUI scaling factor, for improved compatibili
[gui.gamesetup]
enabletips = true ; Enable/Disable tips during gamesetup (for newcomers)
[gui.menu]
limitfps = true ; Limit FPS in the menus and loading screen
[gui.session]
camerajump.threshold = 40 ; How close do we have to be to the actual location in order to jump back to the previous one?
timeelapsedcounter = false ; Show the game duration in the top right corner

View File

@ -171,6 +171,7 @@ function setupControl(option, i, category)
if (callbackFunction)
Engine[callbackFunction](+this.value);
updateOptionPanel();
control.tooltip = this.value;
};
}(key, callbackFunction, minvalue, maxvalue);

View File

@ -205,10 +205,16 @@
"parameters": { "config": "vsync" }
},
{
"type": "boolean",
"label": "Limit FPS in Menus",
"tooltip": "Limit FPS to 50 in all menus, to save power.",
"parameters": { "config": "gui.menu.limitfps" }
"type": "slider",
"label": "FPS throttling in menus",
"tooltip": "To save CPU workload, throttle render frequency in all menus. Set to maximum to disable throttling.",
"parameters": { "config": "adaptivefps.menu", "min": 20, "max": 100 }
},
{
"type": "slider",
"label": "FPS throttling in games",
"tooltip": "To save CPU workload, throttle render frequency in running games. Set to maximum to disable throttling.",
"parameters": { "config": "adaptivefps.session", "min": 20, "max": 100 }
}
],
"soundSetting":

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -31,6 +31,8 @@ that of Atlas depending on commandline parameters.
#define MINIMAL_PCH 2
#include "lib/precompiled.h"
#include <chrono>
#include "lib/debug.h"
#include "lib/status.h"
#include "lib/secure_crt.h"
@ -92,6 +94,8 @@ void kill_mainloop();
static int g_ResizedW;
static int g_ResizedH;
static std::chrono::high_resolution_clock::time_point lastFrameTime;
// main app message handler
static InReaction MainInputHandler(const SDL_Event_* ev)
{
@ -178,6 +182,31 @@ static void PumpEvents()
g_TouchInput.Frame();
}
/**
* Optionally throttle the render frequency in order to
* prevent 100% workload of the currently used CPU core.
*/
inline static void LimitFPS()
{
if (g_VSync)
return;
double fpsLimit = 0.0;
CFG_GET_VAL(g_Game && g_Game->IsGameStarted() ? "adaptivefps.session" : "adaptivefps.menu", fpsLimit);
// Keep in sync with options.json
if (fpsLimit < 20.0 || fpsLimit >= 100.0)
return;
double wait = 1000.0 / fpsLimit -
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - lastFrameTime).count() / 1000.0;
if (wait > 0.0)
SDL_Delay(wait);
lastFrameTime = std::chrono::high_resolution_clock::now();
}
static int ProgressiveLoad()
{
@ -275,7 +304,7 @@ static void Frame()
// If we are not running a multiplayer game, disable updates when the game is
// minimized or out of focus and relinquish the CPU a bit, in order to make
// debugging easier.
if(g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus)
if (g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus)
{
PROFILE3("non-focus delay");
need_update = false;
@ -283,22 +312,6 @@ static void Frame()
SDL_Delay(10);
}
// Throttling: limit update and render frequency to the minimum to 50 FPS
// in the "inactive" state, so that other windows get enough CPU time,
// (and it's always nice for power+thermal management).
// TODO: when the game performance is high enough, implementing a limit for
// in-game framerate might be sensible.
const float maxFPSMenu = 50.0;
bool limit_fps = false;
CFG_GET_VAL("gui.menu.limitfps", limit_fps);
if (limit_fps && (!g_Game || !g_Game->IsGameStarted()))
{
float remainingFrameTime = (1000.0 / maxFPSMenu) - realTimeSinceLastFrame;
if (remainingFrameTime > 0)
SDL_Delay(remainingFrameTime);
}
// this scans for changed files/directories and reloads them, thus
// allowing hotloading (changes are immediately assimilated in-game).
ReloadChangedFiles();
@ -351,7 +364,7 @@ static void Frame()
g_Console->Update(realTimeSinceLastFrame);
ogl_WarnIfError();
if(need_render)
if (need_render)
{
Render();
@ -363,6 +376,8 @@ static void Frame()
g_Profiler.Frame();
g_GameRestarted = false;
LimitFPS();
}