Move continuous render loop to interface (now class)

This commit is contained in:
JeremyStar™ 2024-07-26 13:22:16 +02:00
parent 7f324090c1
commit 9c48c3c756
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
2 changed files with 72 additions and 49 deletions

View file

@ -22,9 +22,7 @@ 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;
@ -32,12 +30,11 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
@Getter @Getter
public abstract class GlfwManagementClass implements ApiManagementClass { public abstract class GlfwManagementClass extends ApiManagementClass {
/** /**
* Contains the {@link LoggerInstance} for this class. * Contains the {@link LoggerInstance} for this class.
* *
@ -83,44 +80,6 @@ public abstract class GlfwManagementClass implements ApiManagementClass {
if (!Miscellaneous.onMainThread()) if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException(); throw new NotOnMainThreadException();
AtomicReference<LinkedHashMap<@NotNull Window, @NotNull Throwable>> output = new AtomicReference<>(new LinkedHashMap<>()); // runRenderLoop output return super.runRenderLoopContinuously(frameCode);
long renderTime; // Amount of time spent rendering
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' is empty
while (output.get().isEmpty()) {
renderTime = Miscellaneous.measureExecutionTime(() -> {
output.set(runRenderLoop());
frameCode.run();
});
// TODO v-sync is currently broken, monitor api needs to be implemented first
// 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
}
}
return output.get();
} }
} }

View file

@ -19,33 +19,57 @@
package de.staropensource.sosengine.graphics.classes; package de.staropensource.sosengine.graphics.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 lombok.AccessLevel;
import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* The interface for Graphics API management classes. * The interface for Graphics API management classes.
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" })
public interface ApiManagementClass { public abstract class ApiManagementClass {
/**
* Contains the logger instance for this class.
*
* @since v1-alpha2
*
* -- GETTER --
* Returns the logger instance for this class.
*
* @return logger instance
* @since v1-alpha2
*/
@Getter(value = AccessLevel.PROTECTED)
private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE));
/** /**
* Returns if this Graphics API must be interacted with on the main thread. * Returns if this Graphics API must be interacted with on the main thread.
* *
* @return {@code true} if Graphics API must be interacted with on the main thread, {@code false} otherwise * @return {@code true} if Graphics API must be interacted with on the main thread, {@code false} otherwise
* @since v1-alpha2 * @since v1-alpha2
*/ */
boolean mustRunOnMainThread(); public abstract boolean mustRunOnMainThread();
/** /**
* Runs the render loop <b>once</b>. * Runs the render loop <b>once</b>.
* To run the render loop continuously, see {@link #runRenderLoopContinuously()}. * To run the render loop continuously, see {@link #runRenderLoopContinuously(Runnable)}.
* *
* @return map of windows and their thrown throwables * @return map of windows and their thrown throwables
* @since v1-alpha2 * @since v1-alpha2
*/ */
LinkedHashMap<@NotNull Window, @NotNull Throwable> runRenderLoop(); public abstract LinkedHashMap<@NotNull Window, @NotNull Throwable> runRenderLoop();
/** /**
* Runs the render loop <b>for ever</b>. * Runs the render loop <b>for ever</b>.
@ -57,5 +81,45 @@ public interface ApiManagementClass {
* @return see {@link #runRenderLoop()} * @return see {@link #runRenderLoop()}
* @since v1-alpha2 * @since v1-alpha2
*/ */
LinkedHashMap<@NotNull Window, @NotNull Throwable> runRenderLoopContinuously(@NotNull Runnable frameCode); public LinkedHashMap<@NotNull Window, @NotNull Throwable> runRenderLoopContinuously(@NotNull Runnable frameCode) {
AtomicReference<LinkedHashMap<@NotNull Window, @NotNull Throwable>> output = new AtomicReference<>(new LinkedHashMap<>()); // runRenderLoop output
long renderTime; // Amount of time spent rendering
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' is empty
while (output.get().isEmpty()) {
renderTime = Miscellaneous.measureExecutionTime(() -> {
output.set(runRenderLoop());
frameCode.run();
});
// TODO v-sync is currently broken, monitor api needs to be implemented first
// 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
}
}
return output.get();
}
} }