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.
This commit is contained in:
JeremyStar™ 2024-07-26 13:07:17 +02:00
parent 4f9154f5fc
commit b529b7a7af
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D

View file

@ -22,18 +22,17 @@ package de.staropensource.sosengine.graphics.glfw.classes;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.CodePart;
import de.staropensource.sosengine.base.types.logging.LogIssuer; 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.base.utility.Miscellaneous;
import de.staropensource.sosengine.graphics.GraphicsSubsystemConfiguration;
import de.staropensource.sosengine.graphics.classes.ApiManagementClass; import de.staropensource.sosengine.graphics.classes.ApiManagementClass;
import de.staropensource.sosengine.graphics.classes.Window; import de.staropensource.sosengine.graphics.classes.Window;
import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap; import java.util.*;
import java.util.LinkedList;
import java.util.OptionalDouble;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
@ -84,31 +83,41 @@ public abstract class GlfwManagementClass implements ApiManagementClass {
if (!Miscellaneous.onMainThread()) if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException(); throw new NotOnMainThreadException();
long renderTime = 0L; AtomicReference<LinkedHashMap<@NotNull Window, @NotNull Throwable>> output = new AtomicReference<>(new LinkedHashMap<>()); // runRenderLoop output
LinkedList<Long> renderTimes = new LinkedList<>(); long renderTime; // Amount of time spent rendering
AtomicReference<LinkedHashMap<@NotNull Window, @NotNull Throwable>> output = new AtomicReference<>(new LinkedHashMap<>()); long sleepDuration; // Time spent sleeping the thread
LinkedList<Long> 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 (output.get().isEmpty()) {
while (renderTimes.size() >= 10) renderTime = Miscellaneous.measureExecutionTime(() -> {
renderTimes.removeLast();
renderTimes.add(Miscellaneous.measureExecutionTime(() -> {
output.set(runRenderLoop()); output.set(runRenderLoop());
frameCode.run(); frameCode.run();
})); });
renderTime += renderTimes.getLast();
// Report // TODO v-sync is currently broken, monitor api needs to be implemented first
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");
renderTimes.clear(); // Calculate amount of time the thread should spend sleeping
renderTime = 0L; 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
} }
} }