Index: binaries/data/config/default.cfg =================================================================== --- binaries/data/config/default.cfg +++ binaries/data/config/default.cfg @@ -125,6 +125,9 @@ ; 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 @@ [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 Index: binaries/data/mods/public/gui/options/options.json =================================================================== --- binaries/data/mods/public/gui/options/options.json +++ binaries/data/mods/public/gui/options/options.json @@ -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 limit in menus", + "tooltip": "To save CPU workload, throttle render frequency in all menus. From 25 to 100 FPS (maximum disables throttling).", + "parameters": { "config": "adaptivefps.menu", "min": 25, "max": 100 } + }, + { + "type": "slider", + "label": "FPS limit in games", + "tooltip": "To save CPU workload, limit render frequency in running games. From 25 to 100 FPS (maximum disables throttling).", + "parameters": { "config": "adaptivefps.session", "min": 25, "max": 100 } } ], "soundSetting": Index: source/main.cpp =================================================================== --- source/main.cpp +++ source/main.cpp @@ -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 @@ #define MINIMAL_PCH 2 #include "lib/precompiled.h" +#include + #include "lib/debug.h" #include "lib/status.h" #include "lib/secure_crt.h" @@ -92,6 +94,8 @@ static int g_ResizedW; static int g_ResizedH; +std::chrono::high_resolution_clock::time_point g_LastFrameTime; + // main app message handler static InReaction MainInputHandler(const SDL_Event_* ev) { @@ -178,6 +182,28 @@ g_TouchInput.Frame(); } +// Optionally throttle the render frequency in order to +// prevent 100% workload of the currently used CPU core. +inline static void LimitFPS() +{ + double fpsLimit = 0.f; + CFG_GET_VAL(g_Game && g_Game->IsGameStarted() ? "adaptivefps.session" : "adaptivefps.menu", fpsLimit); + + // Keep the maximum in sync with options.json + if (fpsLimit < 20 || fpsLimit >= 100) + return; + + std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); + double wait = 1000.f / fpsLimit - std::chrono::duration_cast(now - g_LastFrameTime).count() / 1000000.f; + + if (wait > 0) + { + SDL_Delay(wait); + debug_printf("%f\n", wait); + } + + g_LastFrameTime = now; +} static int ProgressiveLoad() { @@ -275,7 +301,7 @@ // 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,21 +309,7 @@ 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); - } - + LimitFPS(); // this scans for changed files/directories and reloads them, thus // allowing hotloading (changes are immediately assimilated in-game). @@ -351,7 +363,7 @@ g_Console->Update(realTimeSinceLastFrame); ogl_WarnIfError(); - if(need_render) + if (need_render) { Render();