From 71d3cd400b4a1ebeeb36ea1ae42cf844aec5691c Mon Sep 17 00:00:00 2001 From: Halbear Date: Sat, 16 May 2026 18:03:20 +0100 Subject: [PATCH] Added throttling outside of window focus and update Engine threads to extend a generic thread --- .../Terrain4J/EngineCore/Display/Window.java | 16 ++- .../EngineCore/Logic/EngineConfig.java | 62 ++++++--- .../Terrain4J/EngineCore/Logic/GameLogic.java | 1 + .../Terrain4J/EngineCore/Main/GameCore.java | 22 +++- .../EngineCore/Main/PrimaryRuntime.java | 43 ++++-- .../EngineCore/Threads/EngineThread.java | 123 ++++++++++++++++++ .../EngineCore/Threads/FastTickThread.java | 43 +++++- .../EngineCore/Threads/MainThread.java | 83 +++--------- .../EngineCore/Threads/RenderThread.java | 71 +++------- .../EngineCore/Vulkan/Rendering/Image.java | 8 ++ terrain4j.properties | 8 +- 11 files changed, 325 insertions(+), 155 deletions(-) create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/Threads/EngineThread.java create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Image.java diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java index 643fab6..fdc47e5 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java @@ -3,8 +3,10 @@ package net.halbear.Terrain4J.EngineCore.Display; import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput; import net.halbear.Terrain4J.EngineCore.Input.MouseListener; import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import org.lwjgl.glfw.GLFWImage; import org.lwjgl.glfw.GLFWVidMode; +import org.lwjgl.glfw.GLFWWindowFocusCallback; import org.lwjgl.system.MemoryUtil; import org.tinylog.Logger; @@ -68,7 +70,19 @@ public class Window { IconBuffer.free(); //free the buffer once icon is set so when the program closes there isn't memory still floating around Logger.debug("Freeing icon Buffer"); - + glfwSetWindowFocusCallback(handle, new GLFWWindowFocusCallback() { + @Override + public void invoke(long window, boolean focused) { + if(EngineConfig.getInstance().IsEngineThrottledOnUnfocus()) { + if (focused) { + EngineConfig.getInstance().SetEngineThrottle(false); + } else { + EngineConfig.getInstance().SetEngineThrottle(true); + } + } + PrimaryRuntime.UpdateFrameAccuracy(); + } + }); glfwMakeContextCurrent(handle); if (EngineConfig.VSYNC) glfwSwapInterval(1); else glfwSwapInterval(0); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java index d01ef99..1b60456 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java @@ -21,35 +21,29 @@ public class EngineConfig { private int MainTickRate; private int FastTickRate; private boolean CapMainToTickRate; + private boolean CapFastToTickRate; + private boolean CapPrimaryToTickRate; private int Width; private int Height; public static int FrameRate_PRIMARYTHREAD =0; public static int TPS =0; public static int FrameRate_MAINENGINETHREAD =0; + public static int FrameRate_FASTENGINETHREAD =0; public static int FrameRate_RENDERTHREAD =0; public static int FrameRate_WINDOW =0; public static int RENDERFRAMES =0; public static boolean VSYNC = false; public static boolean ShaderDebug = false; public static boolean RecompileShaders = false; + private static long ThrottleAccuracy = 100000; + private static boolean ThrottleEngine = false; + private static boolean ThrottleEngineOnUnfocus = true; private boolean vkValidated; private String PhysicalDeviceName; private int RequestedImages; private String IconPath = "/WindowResources/Icon/"; private String IconName = "ProgramIcon.png"; - public int GetRequestedImages(){ - return RequestedImages; - } - public boolean GetVSYNC(){ - return VSYNC; - } - public boolean DebugShaders(){ - return ShaderDebug; - } - public boolean RecompileShaders(){ - return RecompileShaders; - } private EngineConfig() { var EngineConfigVar = new Properties(); Path path = Paths.get(""); @@ -90,12 +84,16 @@ public class EngineConfig { if(SuccessfulLoad) { IconName = (EngineConfigVar.getOrDefault("Software_Icon", "ProgramIcon.png").toString()); IconPath = (EngineConfigVar.getOrDefault("Software_Icon_Path", "/WindowResources/Icon/").toString()); - CapMainToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_main_to_tickrate", "false").toString()); + CapMainToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_main_to_tickrate", true).toString()); + CapFastToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_fast_to_tickrate", true).toString()); + CapPrimaryToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_master_to_tickrate", false).toString()); MainTickRate = Integer.parseInt(EngineConfigVar.getOrDefault("main_thread_tickrate", "120").toString()); FastTickRate = Integer.parseInt(EngineConfigVar.getOrDefault("fast_thread_tickrate", "240").toString()); SOFTWARE_TITLE = EngineConfigVar.getOrDefault("Software_Title", "Terrain4J").toString(); PhysicalDeviceName = EngineConfigVar.getOrDefault("PhysicalDeviceName", "").toString(); accuracy = Long.parseLong(EngineConfigVar.getOrDefault("frame_accuracy", DEFAULT_ACCURACY).toString()); + ThrottleAccuracy = Long.parseLong(EngineConfigVar.getOrDefault("throttle_accuracy", DEFAULT_ACCURACY).toString()); + ThrottleEngineOnUnfocus = Boolean.parseBoolean(EngineConfigVar.getOrDefault("throttle_on_unfocus", true).toString()); TickRate = Integer.parseInt(EngineConfigVar.getOrDefault("master_tick_rate", DEFAULT_TICKRATE).toString()); Width = Integer.parseInt(EngineConfigVar.getOrDefault("display_width", "1280").toString()); Height = Integer.parseInt(EngineConfigVar.getOrDefault("display_height", "720").toString()); @@ -110,7 +108,9 @@ public class EngineConfig { try { EngineConfigVar.setProperty("Software_Icon","ProgramIcon.png"); EngineConfigVar.setProperty("Software_Icon_Path","/WindowResources/Icon/"); - EngineConfigVar.setProperty("cap_main_to_tickrate","false"); + EngineConfigVar.setProperty("cap_master_to_tickrate","false"); + EngineConfigVar.setProperty("cap_main_to_tickrate","true"); + EngineConfigVar.setProperty("cap_fast_to_tickrate","true"); EngineConfigVar.setProperty("main_thread_tickrate","120"); EngineConfigVar.setProperty("fast_thread_tickrate","240"); EngineConfigVar.setProperty("Software_Title","Terrain4J Software"); @@ -123,6 +123,8 @@ public class EngineConfig { EngineConfigVar.setProperty("vkValidated","false"); EngineConfigVar.setProperty("Debug_Shaders","false"); EngineConfigVar.setProperty("ShaderRecompiling","true"); + EngineConfigVar.setProperty("throttle_accuracy","100000"); + EngineConfigVar.setProperty("throttle_on_unfocus","true"); EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file"); Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath()); } catch (IOException excp2) { @@ -133,17 +135,33 @@ public class EngineConfig { } } - public boolean VkValidated(){ - return vkValidated; - } + public static synchronized EngineConfig getInstance() { - if (instance == null) { - - instance = new EngineConfig(); - } + if (instance == null) {instance = new EngineConfig();} return instance; } + + public void SetEngineThrottle(boolean isThrottling){ThrottleEngine = isThrottling; } + public boolean IsEngineThrottled(){return ThrottleEngine;} + public boolean IsEngineThrottledOnUnfocus(){return ThrottleEngineOnUnfocus;} + public long GetThrottleAccuracy(){return ThrottleAccuracy;} + public int GetRequestedImages(){ + return RequestedImages; + } + public boolean GetVSYNC(){ + return VSYNC; + } + public boolean DebugShaders(){ + return ShaderDebug; + } + public boolean RecompileShaders(){ + return RecompileShaders; + } + + public boolean VkValidated(){ + return vkValidated; + } public int getWidth(){ return Width; } @@ -151,6 +169,8 @@ public class EngineConfig { return Height; } public boolean GetMainTickCap(){return CapMainToTickRate;} + public boolean GetFastTickCap(){return CapFastToTickRate;} + public boolean GetPrimaryTickCap(){return CapPrimaryToTickRate;} public int GetMainTickrate(){return MainTickRate;} public int GetFastTickrate(){return FastTickRate;} public long getAccuracy() { diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/GameLogic.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/GameLogic.java index 7778a95..7d97549 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/GameLogic.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/GameLogic.java @@ -5,4 +5,5 @@ public interface GameLogic { InitData Initialise(EngineInstance engineInstance); void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds); void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds); + void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java index 1ce8fe7..656bee9 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -18,13 +18,18 @@ public class GameCore implements GameLogic { @Override public InitData Initialise(EngineInstance engineInstance) { var ModelID = "TriangleModel"; - MeshData meshData = new MeshData("triangle-mesh", new float[]{ - -0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, 0.0f, - 0.5f, -0.5f, 0.0f}, - new int[]{0, 1, 2}); List MeshDataList = new ArrayList<>(); - MeshDataList.add(meshData); + for(int i = 0; i < 5; i++){ + float PosXOffset = -1 + (float)Math.random() * 2; + float PosYOffset = -1 + (float)Math.random() * 2; + MeshDataList.add( + new MeshData("triangle-mesh" + i, new float[]{ + PosXOffset, PosYOffset, 0.00f, + PosXOffset + 0.05f,PosYOffset + 0.15f, 0.0f, + PosXOffset + 0.1f, PosYOffset, 0.0f}, + new int[]{0, 1, 2}) + ); + } ModelData modelData = new ModelData(ModelID, MeshDataList); List models = new ArrayList<>(); models.add(modelData); @@ -38,6 +43,11 @@ public class GameCore implements GameLogic { @Override public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) { + + } + + @Override + public void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds) { } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java index 7eecf2a..9b74f4c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java @@ -2,6 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Main; import net.halbear.Terrain4J.EngineCore.Display.Window; import net.halbear.Terrain4J.EngineCore.Logic.*; +import net.halbear.Terrain4J.EngineCore.Threads.FastTickThread; import net.halbear.Terrain4J.EngineCore.Threads.MainThread; import net.halbear.Terrain4J.EngineCore.Threads.RenderThread; import org.tinylog.Logger; @@ -12,36 +13,60 @@ public class PrimaryRuntime { private double TickRate = 0; private static MainThread PrimaryThread; private static RenderThread DrawingThread; + private static FastTickThread FastThread; private static boolean running = true; private static Window window; private static EngineInstance engineInstance; public static int ThreadsOpen = 0; public static boolean CanClose = false; public static long ShutDownStart; + private static long FrameAccuracy; + private static long OriginalFrameAccuracy; + private static boolean CappedToTickRate = false; public PrimaryRuntime(String windowTitle, GameLogic appLogic) { window = new Window(windowTitle); InitData initData = appLogic.Initialise(engineInstance); engineInstance = new EngineInstance(window, new Scene(window)); PrimaryThread = new MainThread(engineInstance, appLogic); - DrawingThread = new RenderThread(window, engineInstance, initData); + FastThread = new FastTickThread(engineInstance, appLogic); + DrawingThread = new RenderThread(window, engineInstance, initData, appLogic); Thread.currentThread().setName("Terrain4J Primary Runtime Thread"); } - - public void UpdateTickRate(){ - TickRate = (double) 1000000000 / (double) EngineConfig.getInstance().getTickRate(); + public static void UpdateFrameAccuracy(){ + if(EngineConfig.getInstance().IsEngineThrottled()){ + Logger.debug("ThrottlingEngine"); + FrameAccuracy = EngineConfig.getInstance().GetThrottleAccuracy(); + } else{ + Logger.debug("UnThrottlingEngine"); + FrameAccuracy= OriginalFrameAccuracy; + } + PrimaryThread.UpdateFrameAccuracy(); + DrawingThread.UpdateFrameAccuracy(); + FastThread.UpdateFrameAccuracy(); } + public void UpdateTickRateThreshold(){ + CappedToTickRate = EngineConfig.getInstance().GetPrimaryTickCap(); + if (CappedToTickRate){ + TickRate = (double) 1000000000 / (double) EngineConfig.getInstance().getTickRate(); + } else{ + TickRate = 0; + } + } + public void run(){ + UpdateTickRateThreshold(); long InitialTime = System.nanoTime(); long updateTime = InitialTime; double FrameDiff =0; double TickDiff =0; double SecondCounter =0; double cycleDiff = 0; - PrimaryThread.StartMainThread(); - DrawingThread.StartRenderThread(); - TickRate = (double) 1000000000 / (double) EngineConfig.getInstance().getTickRate(); - long FrameAccuracy = EngineConfig.getInstance().getAccuracy(); + PrimaryThread.StartThread(); + DrawingThread.StartThread(); + FastThread.StartThread(); + FrameAccuracy = EngineConfig.getInstance().getAccuracy(); + OriginalFrameAccuracy = FrameAccuracy; Logger.debug("Primary Thread Started"); while (!window.shouldClose() && running){ long now = System.nanoTime(); @@ -93,7 +118,7 @@ public class PrimaryRuntime { if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) { Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen); while ((ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0) && VulkanContext.VulkanLayersOpen > -1 && !CanClose) { - if (!DrawingThread.FetchRenderThread().isAlive() && !PrimaryThread.FetchMainThread().isAlive() && ThreadsOpen >0){ + if (!DrawingThread.FetchThread().isAlive() && !PrimaryThread.FetchThread().isAlive() && ThreadsOpen >0){ break; } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/EngineThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/EngineThread.java new file mode 100644 index 0000000..3d7979e --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/EngineThread.java @@ -0,0 +1,123 @@ +package net.halbear.Terrain4J.EngineCore.Threads; + +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Logic.GameLogic; +import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; +import org.tinylog.Logger; + +public class EngineThread implements Runnable{ + public boolean CappedToTickRate; + public int TickRate; + public double TickThreshold = 0; + public static boolean running = true; + public final GameLogic gameLogic; + public int Frames = 0; + public int TickFrames = 0; + public final Thread EngineThread; + public long EngineAccuracy; + public long OriginalAccuracy; + public boolean Throttle; + public String ThreadName; + + public void KillThread(){ + running = false; + } + + public void cleanup(){ + gameLogic.cleanup(); + PrimaryRuntime.ThreadsOpen--; + Logger.debug("Closing "+ThreadName+" Thread, Thread: [{}]",Thread.currentThread().toString()); + } + + public Thread FetchThread(){ + return EngineThread; + } + + public void StartThread(){ + EngineThread.start(); + } + + public EngineThread(EngineInstance engineInstance, GameLogic appLogic, String ThreadName){ + this.ThreadName = ThreadName; + this.gameLogic = appLogic; + Logger.debug("Starting {} Thread",ThreadName); + EngineThread = new Thread(this); + EngineThread.setName("Terrain4J "+ThreadName+" Engine Thread"); + } + + public void UpdateFrameAccuracy(){ + Throttle = EngineConfig.getInstance().IsEngineThrottled(); + if(Throttle){ + EngineAccuracy = EngineConfig.getInstance().GetThrottleAccuracy(); + } else{ + EngineAccuracy= OriginalAccuracy; + } + } + + public void TickEvent(long nsTimeDiff){ + + } + public void FrameEvent(long now, long InitialTime){ + + } + public void CycleEvent(){ + + } + public void SecondEvent(){ + + } + + @Override + public void run() { + PrimaryRuntime.ThreadsOpen++; + long InitialTime = System.nanoTime(); + long updateTime = InitialTime; + double[] FrameTimes = new double[]{0,0,0,0}; + Logger.debug("{} Thread Started",ThreadName); + EngineAccuracy = EngineConfig.getInstance().getAccuracy(); + OriginalAccuracy = EngineAccuracy; + while (running){ + long now = System.nanoTime(); + FrameTimes[0] = now - InitialTime; + FrameTimes[1] += FrameTimes[0]; + FrameTimes[2] += FrameTimes[0]; + FrameTimes[3] += FrameTimes[0]; + if (FrameTimes[1] >= EngineAccuracy){ + FrameEvent(now, InitialTime); + Frames++; + if (FrameTimes[2] >= TickThreshold) { + TickFrames++; + long nsTimeDiff = now - updateTime; + TickEvent(nsTimeDiff); + updateTime = now; + FrameTimes[2] = 0; + } + if (FrameTimes[3] >= 1000000000L){ + FrameTimes[3] = 0; + SecondEvent(); + Frames = 0; + TickFrames = 0; + } + FrameTimes[1] = 0; + } + if(Throttle) { + long endTime = System.nanoTime(); + long LoopFrameDiff = endTime - now; + long sleepTime = ((EngineAccuracy - LoopFrameDiff) / 1000000); + + if (sleepTime > 0) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Logger.error("Thread Sleep Exception [{}]", e); + Thread.currentThread().interrupt(); + break; + } + } + } + InitialTime = now; + } + cleanup(); + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/FastTickThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/FastTickThread.java index a181f1a..c4c062f 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/FastTickThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/FastTickThread.java @@ -1,4 +1,45 @@ package net.halbear.Terrain4J.EngineCore.Threads; -public class FastTickThread { +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Logic.GameLogic; +import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; +import org.tinylog.Logger; + +public class FastTickThread extends EngineThread { + + public FastTickThread(EngineInstance engineInstance, GameLogic appLogic){ + super(engineInstance, appLogic, "Fast"); + UpdateTickRateThreshold(); + } + + @Override + public void TickEvent(long nsTimeDiff){ + gameLogic.UpdateFastThread(PrimaryRuntime.GetEngineInstance(), nsTimeDiff); + } + @Override + public void FrameEvent(long now, long InitialTime){ + + } + @Override + public void CycleEvent(){ + + } + @Override + public void SecondEvent(){ + EngineConfig.FrameRate_FASTENGINETHREAD = Frames; + Logger.info(ThreadName + " Thread FPS: " + EngineConfig.FrameRate_FASTENGINETHREAD + " TPS: " + TickFrames); + } + + public void UpdateTickRateThreshold(){ + CappedToTickRate = EngineConfig.getInstance().GetFastTickCap(); + TickRate = EngineConfig.getInstance().GetFastTickrate(); + if (CappedToTickRate){ + TickThreshold = (double) 1000000000 / (double) TickRate; + } else{ + TickThreshold = 0; + } + } + + } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java index c2e3cd5..be818fb 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java @@ -9,36 +9,24 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import net.halbear.Terrain4J.EngineCore.Main.Scene; import org.tinylog.Logger; -public class MainThread implements Runnable { - private static boolean CappedToTickRate; - private static int TickRate; - private static double TickThreshold; - private static boolean running = true; - private final GameLogic gameLogic; - private int Frames = 0; - private int TickFrames = 0; - private final Thread mainThread; +public class MainThread extends EngineThread { - public void KillThread(){ - running = false; + @Override + public void TickEvent(long nsTimeDiff){ + gameLogic.Update(PrimaryRuntime.GetEngineInstance(), nsTimeDiff); } - public void cleanup(){ - gameLogic.cleanup(); - PrimaryRuntime.ThreadsOpen--; - Logger.debug("Closing Main Thread, Thread: [{}]",Thread.currentThread().toString()); + @Override + public void FrameEvent(long now, long InitialTime){ + gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (now - InitialTime)); } - public Thread FetchMainThread(){ - return mainThread; + @Override + public void CycleEvent(){ + } - public void StartMainThread(){ - mainThread.start(); - } - public MainThread(EngineInstance engineInstance, GameLogic appLogic){ - this.gameLogic = appLogic; - Logger.debug("Starting Main Thread"); - UpdateTickRateThreshold(); - mainThread = new Thread(this); - mainThread.setName("Terrain4J Main Engine Thread"); + @Override + public void SecondEvent(){ + EngineConfig.FrameRate_MAINENGINETHREAD = Frames; + Logger.info(ThreadName + " Thread FPS: " + EngineConfig.FrameRate_MAINENGINETHREAD + " TPS: " + TickFrames); } public void UpdateTickRateThreshold(){ CappedToTickRate = EngineConfig.getInstance().GetMainTickCap(); @@ -49,44 +37,9 @@ public class MainThread implements Runnable { TickThreshold = 0; } } - @Override - public void run() { - PrimaryRuntime.ThreadsOpen++; - long InitialTime = System.nanoTime(); - long updateTime = InitialTime; - double FrameDiff =0; - double TickDiff =0; - double SecondCounter =0; - double cycleDiff = 0; - Logger.debug("Main Thread Started"); - long EngineAccuracy = EngineConfig.getInstance().getAccuracy(); - while (running){ - long now = System.nanoTime(); - cycleDiff = now - InitialTime; - FrameDiff += cycleDiff; - TickDiff += cycleDiff; - SecondCounter += cycleDiff; - if (FrameDiff >= EngineAccuracy){ - gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (now - InitialTime)); - Frames++; - if (TickDiff >= TickThreshold) { - TickFrames++; - long nsTimeDiff = now - updateTime; - gameLogic.Update(PrimaryRuntime.GetEngineInstance(), nsTimeDiff); - updateTime = now; - TickDiff = 0; - } - if (SecondCounter >= 1000000000L){ - SecondCounter = 0; - EngineConfig.FrameRate_MAINENGINETHREAD = Frames; - Logger.info("Main Thread FPS: " + EngineConfig.FrameRate_MAINENGINETHREAD + " TPS: " + TickFrames); - Frames = 0; - TickFrames = 0; - } - FrameDiff = 0; - } - InitialTime = now; - } - cleanup(); + public MainThread(EngineInstance engineInstance, GameLogic appLogic){ + super(engineInstance, appLogic, "Main"); + UpdateTickRateThreshold(); } + } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java index 3c636ac..c159655 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java @@ -2,73 +2,44 @@ package net.halbear.Terrain4J.EngineCore.Threads; import net.halbear.Terrain4J.EngineCore.Display.Render; import net.halbear.Terrain4J.EngineCore.Display.Window; -import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; -import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; -import net.halbear.Terrain4J.EngineCore.Logic.InitData; -import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext; +import net.halbear.Terrain4J.EngineCore.Logic.*; import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import org.tinylog.Logger; -public class RenderThread implements Runnable { - private static boolean running = true; - private int Frames = 0; - private final Thread renderThread; +public class RenderThread extends EngineThread { private final Render render; private Window window; - public RenderThread(Window window, EngineInstance engineInstance, InitData initData) { + public RenderThread(Window window, EngineInstance engineInstance, InitData initData, GameLogic appLogic) { //this.window = window; render = new Render(engineInstance); + super(engineInstance,appLogic,"Render"); render.Initialise(initData); - renderThread = new Thread(this); - renderThread.setName("Terrain4J Vulkan Render Thread"); } - public void KillThread(){ - running = false; + @Override + public void TickEvent(long nsTimeDiff){ + } - public Thread FetchRenderThread(){ - return renderThread; + @Override + public void FrameEvent(long now, long InitialTime){ + render.render(PrimaryRuntime.GetEngineInstance()); } - public void StartRenderThread(){ - renderThread.start(); + @Override + public void CycleEvent(){ + } - private void cleanup() { + @Override + public void SecondEvent(){ + Logger.info("Render FPS: " + Frames); + } + + + @Override + public void cleanup() { render.cleanup(); PrimaryRuntime.ThreadsOpen--; Logger.debug("Closing Render Thread, Thread: [{}]",Thread.currentThread().toString()); if (PrimaryRuntime.ThreadsOpen <= 0 && VulkanContext.VulkanLayersOpen < 0) PrimaryRuntime.CanClose = true; } - @Override - public void run() { - int TotalFrames = 0; - PrimaryRuntime.ThreadsOpen++; - long InitialTime = System.nanoTime(); - double FrameDiff =0; - double SecondCounter =0; - double cycleDiff = 0; - long FrameAccuracy = EngineConfig.getInstance().getAccuracy(); - Logger.debug("Render Thread Started"); - while (running){ - long now = System.nanoTime(); - cycleDiff = now - InitialTime; - FrameDiff += cycleDiff; - SecondCounter += cycleDiff; - if (FrameDiff >= FrameAccuracy){ - Frames++; - if (SecondCounter >= 1000000000L){ - SecondCounter = 0; - //EngineConfig.FrameRate_RENDERTHREAD = Frames; - Logger.info("Render FPS: " + Frames); - Frames = 0; - } - render.render(PrimaryRuntime.GetEngineInstance()); - TotalFrames++; - FrameDiff = 0; - } - InitialTime = now; - } - //PrimaryRuntime.CloseRuntime(); - cleanup(); - } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Image.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Image.java new file mode 100644 index 0000000..13bbb9e --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Image.java @@ -0,0 +1,8 @@ +package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering; + +public class Image { + + public static class ImageData{ + + } +} diff --git a/terrain4j.properties b/terrain4j.properties index e3b88aa..b721d5a 100644 --- a/terrain4j.properties +++ b/terrain4j.properties @@ -8,13 +8,17 @@ display_height=480 display_width=640 #Engine Core Settings -#the precision of frames, set this to 16000 and it will limit the whole engine to 64FPS +#the precision of frames, set this to 16000000 and it will limit the whole engine to 64FPS frame_accuracy=0 +throttle_on_unfocus=true +throttle_accuracy=500000000 #event tick rate for game process master_tick_rate=120 main_thread_tickrate=120 fast_thread_tickrate=240 -cap_main_to_tickrate=false +cap_master_to_tickrate=false +cap_main_to_tickrate=true +cap_fast_to_tickrate=true #Renderer Properties Debug_Shaders = false