From b529b7a7af1a832acb4bf65609fd6d24642eb277 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Fri, 26 Jul 2024 13:07:17 +0200 Subject: [PATCH] Make continuous render loop work (except V-Sync) It works quite good now, but it is broken when V-Sync is turned on as it tries to render at the maximum FPS set and does not respect how fast the monitor renders. I first need to implement a monitor API for it to work. --- .../glfw/classes/GlfwManagementClass.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java index 39853559..1dcc9b57 100644 --- a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java @@ -22,18 +22,17 @@ package de.staropensource.sosengine.graphics.glfw.classes; import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.logging.LogIssuer; +import de.staropensource.sosengine.base.utility.Math; import de.staropensource.sosengine.base.utility.Miscellaneous; +import de.staropensource.sosengine.graphics.GraphicsSubsystemConfiguration; import de.staropensource.sosengine.graphics.classes.ApiManagementClass; import de.staropensource.sosengine.graphics.classes.Window; import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; import lombok.Getter; import org.jetbrains.annotations.NotNull; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.OptionalDouble; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; import static org.lwjgl.glfw.GLFW.*; @@ -84,31 +83,41 @@ public abstract class GlfwManagementClass implements ApiManagementClass { if (!Miscellaneous.onMainThread()) throw new NotOnMainThreadException(); - long renderTime = 0L; - LinkedList renderTimes = new LinkedList<>(); - AtomicReference> output = new AtomicReference<>(new LinkedHashMap<>()); + AtomicReference> output = new AtomicReference<>(new LinkedHashMap<>()); // runRenderLoop output + long renderTime; // Amount of time spent rendering + long sleepDuration; // Time spent sleeping the thread + LinkedList splitDeltaTime = new LinkedList<>(); // Used for calculating the delta time (render time average over one second) + long reportDuration = System.currentTimeMillis(); // Used for determining when to report frame count and delta time + double deltaTime; // Contains the average render time over one second (delta time) - // Run while the output linked map of runRenderLoop is empty + // Run while the 'output' is empty while (output.get().isEmpty()) { - while (renderTimes.size() >= 10) - renderTimes.removeLast(); - - renderTimes.add(Miscellaneous.measureExecutionTime(() -> { + renderTime = Miscellaneous.measureExecutionTime(() -> { output.set(runRenderLoop()); frameCode.run(); - })); - renderTime += renderTimes.getLast(); + }); - // Report - if (renderTime >= 1000) { - OptionalDouble average = renderTimes.stream().mapToDouble(a -> a).average(); - if (average.isPresent()) - logger.info("Delta average: " + average.getAsDouble() + " | Frames/s: " + 1000 / average.getAsDouble()); - else - logger.error("Unable to get delta average and FPS"); + // TODO v-sync is currently broken, monitor api needs to be implemented first - renderTimes.clear(); - renderTime = 0L; + // Calculate amount of time the thread should spend sleeping + sleepDuration = (long) (1d / GraphicsSubsystemConfiguration.getInstance().getMaximumFramesPerSecond() * 1000d) - renderTime; + // Add render and sleep time to list used for calculating the delta time value + splitDeltaTime.add(renderTime + sleepDuration); + + try { + //noinspection BusyWait // true, true + Thread.sleep(sleepDuration); + } catch (InterruptedException exception) { + logger.crash("Rendering loop got interrupted. This is unsupported behaviour.", exception); + } + + // Calculate delta time and frame count every second + if (System.currentTimeMillis() >= reportDuration + 1000) { + deltaTime = Math.getMeanLong(splitDeltaTime); // Calculate delta time + logger.info("Delta time average: " + deltaTime + " | Frames/s: " + 1000 / deltaTime); // Print delta time and frame count to console + + reportDuration = System.currentTimeMillis(); // Update 'reportDuration' + splitDeltaTime.clear(); // Clear 'splitDeltaTime' list } }