From aa7fbd03292a6441ec3d154ea6d4ea1a378efc8b Mon Sep 17 00:00:00 2001
From: Matt Weber <30441572+mweber15@users.noreply.github.com>
Date: Mon, 15 Mar 2021 00:36:27 -0400
Subject: [PATCH 1/4] Add foreground FPS limit

As reported in issue #13, PoB tends to use significant CPU and GPU resources
while in the foreground. This change exposes a foreground frame rate limit that
can be configured via a CVar (vid_fgfps) that defaults to a 30 FPS limit and
allows a 5-120 FPS range. A setting of 30 feels responsive and reduces the
resource usage by a modest amount. CPU usage hovers around 4% on my 16-core
system with this change, as opposed to 6% usage with the current build.
Similarly, GPU usage hovers around 18-20% with the 30 FPS limit and around
25-28% with the current build.

There may be a better place to situate the sleep that is introduced for this,
but this seemed like a reasonable place for someone who is not very familiar
with this code.

I also removed the reference to tiff.lib in the Debug configuration since that
is unused and not a vcpkg dependency.
---
 SimpleGraphic.vcxproj           |  2 +-
 config.h                        |  1 +
 engine/core/core_video.cpp      |  3 +++
 engine/system/sys_video.h       |  2 ++
 engine/system/win/sys_main.cpp  | 11 +++++++++++
 engine/system/win/sys_video.cpp |  2 ++
 6 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/SimpleGraphic.vcxproj b/SimpleGraphic.vcxproj
index 16f239c..8cdfba3 100644
--- a/SimpleGraphic.vcxproj
+++ b/SimpleGraphic.vcxproj
@@ -120,7 +120,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableUAC>false</EnableUAC>
       <AdditionalLibraryDirectories>$(SolutionDir)vcpkg\installed\x86-windows-static\lib;%(AdditionalLibraryDirectories)LuaJIT/src;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-      <AdditionalDependencies>gif.lib;jpeg.lib;lzma.lib;libpng16.lib;lua51.lib;tiff.lib;zlib.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>gif.lib;jpeg.lib;lzma.lib;libpng16.lib;lua51.lib;zlib.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
diff --git a/config.h b/config.h
index f484d5a..6d466dc 100644
--- a/config.h
+++ b/config.h
@@ -18,5 +18,6 @@
 #define CFG_VID_DEFDISPLAY "-1"
 #define CFG_VID_DEFFULLSCREEN "0"
 #define CFG_VID_DEFRESIZABLE "0"
+#define CFG_VID_DEFFGFPS "30"
 #define CFG_VID_MINWIDTH 1280
 #define CFG_VID_MINHEIGHT 720
\ No newline at end of file
diff --git a/engine/core/core_video.cpp b/engine/core/core_video.cpp
index f6bfcf1..e347d6d 100644
--- a/engine/core/core_video.cpp
+++ b/engine/core/core_video.cpp
@@ -48,6 +48,7 @@ class core_video_c: public core_IVideo, public conCmdHandler_c {
 	conVar_c* vid_fullscreen;
 	conVar_c* vid_resizable;
 	conVar_c* vid_last;
+	conVar_c* vid_fgfps;
 
 	void	C_Vid_Apply(IConsole* conHnd, args_c &args);
 	void	C_Vid_ModeList(IConsole* conHnd, args_c &args);
@@ -71,6 +72,7 @@ core_video_c::core_video_c(sys_IMain* sysHnd)
 	vid_fullscreen	= sys->con->Cvar_Add("vid_fullscreen", CV_ARCHIVE, CFG_VID_DEFFULLSCREEN);
 	vid_resizable	= sys->con->Cvar_Add("vid_resizable", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFRESIZABLE, 0, 3);
 	vid_last		= sys->con->Cvar_Add("vid_last", CV_ARCHIVE, "");
+	vid_fgfps		= sys->con->Cvar_Add("vid_fgfps", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFFGFPS, 5, 120);
 
 	Cmd_Add("vid_apply", 0, "", this, &core_video_c::C_Vid_Apply);
 	Cmd_Add("vid_modeList", 0, "", this, &core_video_c::C_Vid_ModeList);
@@ -111,6 +113,7 @@ void core_video_c::Apply(bool shown)
 	set.depth = 0;
 	set.minSize[0] = CFG_VID_MINWIDTH;
 	set.minSize[1] = CFG_VID_MINHEIGHT;
+	set.fgfps = vid_fgfps->intVal;
 	sys->video->Apply(&set);
 }
 
diff --git a/engine/system/sys_video.h b/engine/system/sys_video.h
index 461a95e..1e8a39b 100644
--- a/engine/system/sys_video.h
+++ b/engine/system/sys_video.h
@@ -22,6 +22,7 @@ struct sys_vidSave_s {
 	int		size[2] = {};
 	int		pos[2] = {};
 	bool	maximised = false;
+	int		fgfps = 0;
 };
 
 // Video settings structure
@@ -32,6 +33,7 @@ struct sys_vidSet_s {
 	int		mode[2] = {};	// Resolution or window size
 	int		depth = 0;		// Bit depth
 	int		minSize[2] = {};	// Minimum size for resizable windows
+	int		fgfps = 0;		// Foreground FPS limit
 	sys_vidSave_s save; // Saved state
 };
 
diff --git a/engine/system/win/sys_main.cpp b/engine/system/win/sys_main.cpp
index 84ab748..42504ec 100644
--- a/engine/system/win/sys_main.cpp
+++ b/engine/system/win/sys_main.cpp
@@ -11,6 +11,9 @@
 
 #include <eh.h>
 
+#include <chrono>
+#include <thread>
+
 // ======
 // Locals
 // ======
@@ -777,7 +780,15 @@ bool sys_main_c::Run(int argc, char** argv)
 		while (exitFlag == false) {
 			RunMessages();
 
+			const auto frameStart = std::chrono::high_resolution_clock::now();
 			core->Frame();
+			const auto frameEnd = std::chrono::high_resolution_clock::now();
+			using FpMilliseconds = std::chrono::duration<float, std::chrono::milliseconds::period>;
+			const auto frameDuration = std::chrono::duration_cast<FpMilliseconds>(frameEnd - frameStart);
+			const auto minimumFrameDuration = FpMilliseconds(1000.0f / video->vid.fgfps);
+			if (frameDuration < minimumFrameDuration) {
+				std::this_thread::sleep_for(minimumFrameDuration - frameDuration);
+			}
 
 			if (threadError) {
 				Error(threadError);
diff --git a/engine/system/win/sys_video.cpp b/engine/system/win/sys_video.cpp
index 6d8d81b..891c8a7 100644
--- a/engine/system/win/sys_video.cpp
+++ b/engine/system/win/sys_video.cpp
@@ -275,6 +275,8 @@ int sys_video_c::Apply(sys_vidSet_s* set)
 	vid.size[0] = wrec.right;
 	vid.size[1] = wrec.bottom;
 
+	vid.fgfps = cur.fgfps;
+
 	// Process any messages generated during application
 	sys->RunMessages();
 

From 2dec7930bf1171d4a22ed3b7642bd20c62c85d04 Mon Sep 17 00:00:00 2001
From: Matt Weber <30441572+mweber15@users.noreply.github.com>
Date: Tue, 16 Mar 2021 05:01:18 -0400
Subject: [PATCH 2/4] Revert tiff.lib removal

---
 SimpleGraphic.vcxproj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/SimpleGraphic.vcxproj b/SimpleGraphic.vcxproj
index 8cdfba3..16f239c 100644
--- a/SimpleGraphic.vcxproj
+++ b/SimpleGraphic.vcxproj
@@ -120,7 +120,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableUAC>false</EnableUAC>
       <AdditionalLibraryDirectories>$(SolutionDir)vcpkg\installed\x86-windows-static\lib;%(AdditionalLibraryDirectories)LuaJIT/src;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
-      <AdditionalDependencies>gif.lib;jpeg.lib;lzma.lib;libpng16.lib;lua51.lib;zlib.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>gif.lib;jpeg.lib;lzma.lib;libpng16.lib;lua51.lib;tiff.lib;zlib.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

From ab3f87db23dea1294ce550f2a95067bfab25796c Mon Sep 17 00:00:00 2001
From: Matt Weber <30441572+mweber15@users.noreply.github.com>
Date: Tue, 16 Mar 2021 05:25:51 -0400
Subject: [PATCH 3/4] Incorporate review feedback

---
 config.h                        |  1 +
 engine/core/core_video.cpp      |  3 +++
 engine/system/sys_video.h       |  2 ++
 engine/system/win/sys_main.cpp  | 11 -----------
 engine/system/win/sys_video.cpp |  1 +
 ui_main.cpp                     | 20 ++++++++++++++++----
 6 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/config.h b/config.h
index 6d466dc..21f388b 100644
--- a/config.h
+++ b/config.h
@@ -19,5 +19,6 @@
 #define CFG_VID_DEFFULLSCREEN "0"
 #define CFG_VID_DEFRESIZABLE "0"
 #define CFG_VID_DEFFGFPS "30"
+#define CFG_VID_DEFBGFPS "5"
 #define CFG_VID_MINWIDTH 1280
 #define CFG_VID_MINHEIGHT 720
\ No newline at end of file
diff --git a/engine/core/core_video.cpp b/engine/core/core_video.cpp
index e347d6d..fbe0b25 100644
--- a/engine/core/core_video.cpp
+++ b/engine/core/core_video.cpp
@@ -49,6 +49,7 @@ class core_video_c: public core_IVideo, public conCmdHandler_c {
 	conVar_c* vid_resizable;
 	conVar_c* vid_last;
 	conVar_c* vid_fgfps;
+	conVar_c* vid_bgfps;
 
 	void	C_Vid_Apply(IConsole* conHnd, args_c &args);
 	void	C_Vid_ModeList(IConsole* conHnd, args_c &args);
@@ -73,6 +74,7 @@ core_video_c::core_video_c(sys_IMain* sysHnd)
 	vid_resizable	= sys->con->Cvar_Add("vid_resizable", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFRESIZABLE, 0, 3);
 	vid_last		= sys->con->Cvar_Add("vid_last", CV_ARCHIVE, "");
 	vid_fgfps		= sys->con->Cvar_Add("vid_fgfps", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFFGFPS, 5, 120);
+	vid_bgfps		= sys->con->Cvar_Add("vid_bgfps", CV_ARCHIVE | CV_CLAMP, CFG_VID_DEFBGFPS, 5, 120);
 
 	Cmd_Add("vid_apply", 0, "", this, &core_video_c::C_Vid_Apply);
 	Cmd_Add("vid_modeList", 0, "", this, &core_video_c::C_Vid_ModeList);
@@ -114,6 +116,7 @@ void core_video_c::Apply(bool shown)
 	set.minSize[0] = CFG_VID_MINWIDTH;
 	set.minSize[1] = CFG_VID_MINHEIGHT;
 	set.fgfps = vid_fgfps->intVal;
+	set.bgfps = vid_bgfps->intVal;
 	sys->video->Apply(&set);
 }
 
diff --git a/engine/system/sys_video.h b/engine/system/sys_video.h
index 1e8a39b..b5bff56 100644
--- a/engine/system/sys_video.h
+++ b/engine/system/sys_video.h
@@ -23,6 +23,7 @@ struct sys_vidSave_s {
 	int		pos[2] = {};
 	bool	maximised = false;
 	int		fgfps = 0;
+	int		bgfps = 0;
 };
 
 // Video settings structure
@@ -34,6 +35,7 @@ struct sys_vidSet_s {
 	int		depth = 0;		// Bit depth
 	int		minSize[2] = {};	// Minimum size for resizable windows
 	int		fgfps = 0;		// Foreground FPS limit
+	int		bgfps = 0;		// Background FPS limit
 	sys_vidSave_s save; // Saved state
 };
 
diff --git a/engine/system/win/sys_main.cpp b/engine/system/win/sys_main.cpp
index 42504ec..84ab748 100644
--- a/engine/system/win/sys_main.cpp
+++ b/engine/system/win/sys_main.cpp
@@ -11,9 +11,6 @@
 
 #include <eh.h>
 
-#include <chrono>
-#include <thread>
-
 // ======
 // Locals
 // ======
@@ -780,15 +777,7 @@ bool sys_main_c::Run(int argc, char** argv)
 		while (exitFlag == false) {
 			RunMessages();
 
-			const auto frameStart = std::chrono::high_resolution_clock::now();
 			core->Frame();
-			const auto frameEnd = std::chrono::high_resolution_clock::now();
-			using FpMilliseconds = std::chrono::duration<float, std::chrono::milliseconds::period>;
-			const auto frameDuration = std::chrono::duration_cast<FpMilliseconds>(frameEnd - frameStart);
-			const auto minimumFrameDuration = FpMilliseconds(1000.0f / video->vid.fgfps);
-			if (frameDuration < minimumFrameDuration) {
-				std::this_thread::sleep_for(minimumFrameDuration - frameDuration);
-			}
 
 			if (threadError) {
 				Error(threadError);
diff --git a/engine/system/win/sys_video.cpp b/engine/system/win/sys_video.cpp
index 891c8a7..6eedae3 100644
--- a/engine/system/win/sys_video.cpp
+++ b/engine/system/win/sys_video.cpp
@@ -276,6 +276,7 @@ int sys_video_c::Apply(sys_vidSet_s* set)
 	vid.size[1] = wrec.bottom;
 
 	vid.fgfps = cur.fgfps;
+	vid.bgfps = cur.bgfps;
 
 	// Process any messages generated during application
 	sys->RunMessages();
diff --git a/ui_main.cpp b/ui_main.cpp
index f9622e0..17be353 100644
--- a/ui_main.cpp
+++ b/ui_main.cpp
@@ -6,6 +6,9 @@
 
 #include "ui_local.h"
 
+#include <chrono>
+#include <thread>
+
 // ======
 // Locals
 // ======
@@ -373,6 +376,8 @@ void ui_main_c::ScriptInit()
 
 void ui_main_c::Frame()
 {
+	const auto frameStart = std::chrono::high_resolution_clock::now();
+	auto fpsLimit = sys->video->vid.fgfps;
 	if (!sys->video->IsVisible() || sys->conWin->IsVisible() || restartFlag || didExit) {
 		framesSinceWindowHidden = 0;
 	}
@@ -380,8 +385,7 @@ void ui_main_c::Frame()
 		framesSinceWindowHidden++;
 	}
 	else if (!sys->video->IsActive() && !sys->video->IsCursorOverWindow()) {
-		sys->Sleep(100);
-		return;
+		fpsLimit = sys->video->vid.bgfps;
 	}	
 	
 	if (renderer) {
@@ -425,8 +429,8 @@ void ui_main_c::Frame()
 	}
 
 	//sys->con->Printf("Finishing up...\n");
-	if ( !sys->video->IsActive() ) {
-		sys->Sleep(100);
+	if ( sys->video->IsActive() ) {
+		fpsLimit = sys->video->vid.fgfps;
 	}
 
 	while (restartFlag) {
@@ -436,6 +440,14 @@ void ui_main_c::Frame()
 		}
 		ScriptInit();
 	}
+	
+	using FpMilliseconds = std::chrono::duration<float, std::chrono::milliseconds::period>;
+	const auto minimumFrameDuration = FpMilliseconds(1000.0f / fpsLimit);
+	const auto frameEnd = std::chrono::high_resolution_clock::now();
+	const auto frameDuration = std::chrono::duration_cast<FpMilliseconds>(frameEnd - frameStart);
+	if (frameDuration < minimumFrameDuration) {
+	  std::this_thread::sleep_for(minimumFrameDuration - frameDuration);
+	}
 }
 
 void ui_main_c::ScriptShutdown()

From 9f28e3ee80c9dd8dbf5a0b30007af7650cdd0e96 Mon Sep 17 00:00:00 2001
From: Matt Weber <30441572+mweber15@users.noreply.github.com>
Date: Tue, 16 Mar 2021 05:30:26 -0400
Subject: [PATCH 4/4] Formatting

---
 engine/core/core_video.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/engine/core/core_video.cpp b/engine/core/core_video.cpp
index fbe0b25..2e1b630 100644
--- a/engine/core/core_video.cpp
+++ b/engine/core/core_video.cpp
@@ -74,7 +74,7 @@ core_video_c::core_video_c(sys_IMain* sysHnd)
 	vid_resizable	= sys->con->Cvar_Add("vid_resizable", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFRESIZABLE, 0, 3);
 	vid_last		= sys->con->Cvar_Add("vid_last", CV_ARCHIVE, "");
 	vid_fgfps		= sys->con->Cvar_Add("vid_fgfps", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFFGFPS, 5, 120);
-	vid_bgfps		= sys->con->Cvar_Add("vid_bgfps", CV_ARCHIVE | CV_CLAMP, CFG_VID_DEFBGFPS, 5, 120);
+	vid_bgfps		= sys->con->Cvar_Add("vid_bgfps", CV_ARCHIVE|CV_CLAMP, CFG_VID_DEFBGFPS, 5, 120);
 
 	Cmd_Add("vid_apply", 0, "", this, &core_video_c::C_Vid_Apply);
 	Cmd_Add("vid_modeList", 0, "", this, &core_video_c::C_Vid_ModeList);