Added Debugger and logging

This commit is contained in:
Harrison Corlett 2026-01-16 10:21:37 +00:00
parent 773f02f11d
commit 71bd825553
45 changed files with 96 additions and 785 deletions

View file

@ -2,10 +2,13 @@ package net.halbear.Executable;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import org.tinylog.Logger;
public class Init {
public static void main(String[] args){
Logger.info("Launching Software");
var GameEngine = new PrimaryRuntime("Terrain4J", new GameCore());
GameEngine.run();
Logger.info("Launched Engine");
}
}

View file

@ -4,7 +4,9 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFWVulkan;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.vulkan.*;
import org.tinylog.Logger;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
@ -14,21 +16,28 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.EXTDebugUtils.vkCreateDebugUtilsMessengerEXT;
import static org.lwjgl.vulkan.EXTDebugUtils.vkDestroyDebugUtilsMessengerEXT;
import static org.lwjgl.vulkan.EXTDebugUtils.*;
import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK14.VK_API_VERSION_1_4;
public class VulkanInstance {
public static final int MESSAGE_SEVERITY_BITMASK = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
public static final int MESSAGE_TYPE_BITMASK = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
private static final String DBG_CALL_BACK_PREF = "VkDebugUtilsCallback, {}";
private static final String VALIDATION_LAYER = "VK_LAYER_KHRONOS_validation";
private static final String PORTABILITY_EXTENSION = "VK_KHR_portability_enumeration";
private static VkInstance vkInstance;
private final VkInstance vkInstance;
private VkDebugUtilsMessengerCreateInfoEXT DebugUtils;
private long DebugHandle;
public VulkanInstance(boolean validate){
Logger.debug("Initialising Vulkan Instance");
try (MemoryStack MemStack = MemoryStack.stackPush()) {
ByteBuffer appShortName = MemStack.UTF8("Terrain4J");
var appInfo = VkApplicationInfo.calloc(MemStack).sType$Default().pApplicationName(appShortName).applicationVersion(1).pEngineName(appShortName).engineVersion(3).apiVersion(VK_API_VERSION_1_4);
@ -40,12 +49,15 @@ public class VulkanInstance {
boolean SupportsValidation = validate;
if (validate && ValidationLayerCount == 0){
SupportsValidation = false;
Logger.warn("No Layers Found to Validate, continuing without validation");
}
Logger.debug("Validation:{}", SupportsValidation);
//once its done the validation layers, transform it into a pointer (null terminated string to be exact)
PointerBuffer RequiredLayers = null;
if (SupportsValidation){
RequiredLayers = MemStack.mallocPointer(ValidationLayerCount);
for(int i = 0; i < ValidationLayerCount; i++){
Logger.debug("Using Validation Layer:{}", ValidationLayers.get(i));
RequiredLayers.put(i, MemStack.ASCII(ValidationLayers.get(i)));
}
}
@ -72,6 +84,11 @@ public class VulkanInstance {
RequiredExtensions.put(ExtraExtensions.get(i));
}
RequiredExtensions.flip();
long extension = MemoryUtil.NULL;
if(SupportsValidation){
DebugUtils = CreateDebugCallBack();
extension = DebugUtils.address();
}
var InstanceInfo = VkInstanceCreateInfo.calloc(MemStack)
.sType$Default()
.pApplicationInfo(appInfo)
@ -83,6 +100,13 @@ public class VulkanInstance {
PointerBuffer PointerInstance = MemStack.mallocPointer(1);
vkCheck(vkCreateInstance(InstanceInfo,null,PointerInstance), "Error Creating Vulkan Instance");
vkInstance = new VkInstance(PointerInstance.get(0),InstanceInfo);
DebugHandle = VK_NULL_HANDLE;
if(SupportsValidation){
LongBuffer LongBuffer = MemStack.mallocLong(1);
vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, DebugUtils, null, LongBuffer), "Error Creating Handle");
DebugHandle = LongBuffer.get(0);
}
}
}
private Set<String> getSupportedInstanceExtensions(){
@ -91,6 +115,7 @@ public class VulkanInstance {
IntBuffer ExtensionsBuffer = MemStack.callocInt(1);
vkEnumerateInstanceExtensionProperties((String)null,ExtensionsBuffer, null);
int ExtensionsCount = ExtensionsBuffer.get(0);
Logger.debug("Instance Extension Count:[{}]", ExtensionsCount);
var InstanceExtensionsProps = VkExtensionProperties.calloc(ExtensionsCount, MemStack);
vkEnumerateInstanceExtensionProperties((String)null,ExtensionsBuffer, InstanceExtensionsProps);
@ -98,7 +123,8 @@ public class VulkanInstance {
VkExtensionProperties Properties = InstanceExtensionsProps.get(i);
String ExtensionName = Properties.extensionNameString();
InstanceExtensions.add(ExtensionName);
}
Logger.trace("Supported Instance Extension [{}]", ExtensionName);
}
}
return InstanceExtensions;
}
@ -107,6 +133,7 @@ public class VulkanInstance {
IntBuffer LayersArray = MemStack.callocInt(1);
vkEnumerateInstanceLayerProperties(LayersArray, null);
int Layers = LayersArray.get(0);
Logger.debug("Validation Layer Count:{}", Layers);
var PropertiesBuffer = VkLayerProperties.calloc(Layers, MemStack);
vkEnumerateInstanceLayerProperties(LayersArray, PropertiesBuffer);
List<String> SupportedLayers = new ArrayList<>();
@ -114,6 +141,7 @@ public class VulkanInstance {
VkLayerProperties properties = PropertiesBuffer.get(i);
String LayerName = properties.layerNameString();
SupportedLayers.add(LayerName);
Logger.trace("Supported Layer [{}]", LayerName);
}
List<String> LayersToUse = new ArrayList<>();
if (SupportedLayers.contains(VALIDATION_LAYER)) {
@ -123,10 +151,39 @@ public class VulkanInstance {
}
}
public void cleanup() {
Logger.debug("Closing Vulkan instance");
if(DebugHandle != VK_NULL_HANDLE){
vkDestroyDebugUtilsMessengerEXT(vkInstance, DebugHandle, null);
}
vkDestroyInstance(vkInstance, null);
if(DebugUtils != null){
DebugUtils.pfnUserCallback().free();
DebugUtils.free();
}
}
public VkInstance getVkInstance() {
return vkInstance;
}
private static VkDebugUtilsMessengerCreateInfoEXT CreateDebugCallBack(){
return VkDebugUtilsMessengerCreateInfoEXT
.calloc()
.sType$Default()
.messageSeverity(MESSAGE_SEVERITY_BITMASK)
.messageType(MESSAGE_TYPE_BITMASK)
.pfnUserCallback((messageSeverity, messageTypes, pCallbackData,pUserData) -> {
VkDebugUtilsMessengerCallbackDataEXT callBackData = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData);
if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
Logger.info(DBG_CALL_BACK_PREF, callBackData.pMessageString());
} else if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
Logger.warn(DBG_CALL_BACK_PREF, callBackData.pMessageString());
} else if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
Logger.error(DBG_CALL_BACK_PREF, callBackData.pMessageString());
} else {
Logger.debug(DBG_CALL_BACK_PREF, callBackData.pMessageString());
}
return VK_FALSE;
});
}
}

View file

@ -2,7 +2,7 @@ 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.Globals;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.system.MemoryUtil;
@ -48,7 +48,7 @@ public class Window {
});
glfwMakeContextCurrent(handle);
if (Globals.VSYNC) glfwSwapInterval(1);
if (EngineConfig.VSYNC) glfwSwapInterval(1);
else glfwSwapInterval(0);
mouseInput = new MouseListener(handle);
}
@ -69,22 +69,22 @@ public class Window {
return mouseInput;
}
public void pollEvents() {
if (displayFPS) glfwSetWindowTitle(handle, "Terrain 4J Engine - FPS: " + Globals.FrameRate_PRIMARYTHREAD + " TPS: " + Globals.TPS + " RenderFPS: " + Globals.FrameRate_RENDER + " VSYNC: " + Globals.VSYNC);
if (displayFPS) glfwSetWindowTitle(handle, "Terrain 4J Engine - FPS: " + EngineConfig.FrameRate_PRIMARYTHREAD + " TPS: " + EngineConfig.TPS + " RenderFPS: " + EngineConfig.FrameRate_RENDER + " VSYNC: " + EngineConfig.VSYNC);
if (keyboardInput.keySinglePress(GLFW_KEY_V)) {
SetVsync();
}
keyboardInput.input();
mouseInput.input();
Globals.RENDERFRAMES++;
EngineConfig.RENDERFRAMES++;
}
public void SetVsync(){
if (Globals.VSYNC) {
if (EngineConfig.VSYNC) {
glfwSwapInterval(0);
Globals.VSYNC = false;
EngineConfig.VSYNC = false;
}
else {
glfwSwapInterval(1);
Globals.VSYNC = true;
EngineConfig.VSYNC = true;
}
}
public void setShouldClose() {

View file

@ -1,95 +0,0 @@
package net.halbear.Terrain4J.EngineCore.Logic;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.Logger;
public class Globals {
private static final long DEFAULT_ACCURACY = 0;
private static final int DEFAULT_TICKRATE = 60;
private static final int DEFAULT_WIDTH = 640;
private static final int DEFAULT_HEIGHT = 480;
private static final String FILENAME = "terrain4j.properties";
private static Globals instance;
private long accuracy;
private int TickRate;
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_RENDER =0;
public static int RENDERFRAMES =0;
public static boolean VSYNC = false;
private boolean vkValidated;
private Globals() {
var EngineConfig = new Properties();
Path path = Paths.get("");
InputStream stream = Globals.class.getResourceAsStream(path.toAbsolutePath().toString() + "/" + FILENAME);
boolean SuccessfulLoad = false;
if (stream != null) {
try {
EngineConfig.load(stream);
SuccessfulLoad = true;
} catch (IOException excp) {
System.out.println(excp.getMessage());
}
}
if (SuccessfulLoad){
accuracy = Long.parseLong(EngineConfig.getOrDefault("frame_accuracy", DEFAULT_ACCURACY).toString());
TickRate = Integer.parseInt(EngineConfig.getOrDefault("main_tick_rate", DEFAULT_TICKRATE).toString());
Width = Integer.parseInt(EngineConfig.getOrDefault("display_width", DEFAULT_TICKRATE).toString());
Height = Integer.parseInt(EngineConfig.getOrDefault("display_height", DEFAULT_TICKRATE).toString());
VSYNC = Boolean.parseBoolean(EngineConfig.getOrDefault("vsync", false).toString());
try {
assert stream != null;
stream.close();
} catch(IOException excp) {
System.out.println(excp.getMessage());
}
} else{
try {
EngineConfig.setProperty("frame_accuracy", "0");
EngineConfig.setProperty("main_tick_rate", "60");
EngineConfig.setProperty("display_width", "640");
EngineConfig.setProperty("display_height", "480");
EngineConfig.setProperty("vsync", "false");
EngineConfig.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file");
} catch (IOException excp2) {
System.out.println(excp2.getMessage());
}
accuracy = DEFAULT_ACCURACY;
TickRate = DEFAULT_TICKRATE;
}
vkValidated = Boolean.parseBoolean(EngineConfig.getOrDefault("vkValidated", false).toString());
}
public boolean VkValidated(){
return vkValidated;
}
public static synchronized Globals getInstance() {
if (instance == null) {
instance = new Globals();
}
return instance;
}
public int getWidth(){
return Width;
}
public int getHeight(){
return Height;
}
public long getAccuracy() {
return accuracy;
}
public int getTickRate() {
return TickRate;
}
}

View file

@ -5,7 +5,7 @@ import net.halbear.Terrain4J.EngineCore.Display.VulkanInstance;
public class VulkanContext {
private final VulkanInstance Instance;
public VulkanContext(){
var EngineGlobals = Globals.getInstance();
var EngineGlobals = EngineConfig.getInstance();
Instance = new VulkanInstance(EngineGlobals.VkValidated());
}

View file

@ -2,7 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Main;
import net.halbear.Terrain4J.EngineCore.Display.Render;
import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Logic.Globals;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
@ -42,11 +42,11 @@ public class PrimaryRuntime {
FrameDiff += tickDiff;
TickDiff += tickDiff;
SecondCounter += tickDiff;
if (FrameDiff >= Globals.getInstance().getAccuracy()){
if (FrameDiff >= EngineConfig.getInstance().getAccuracy()){
window.pollEvents();
gameLogic.Input(engineInstance, (now - InitialTime)/ 1000000);
Frames++;
if (TickDiff/1000 >= (double) 1000000 / (double)Globals.getInstance().getTickRate()) {
if (TickDiff/1000 >= (double) 1000000 / (double) EngineConfig.getInstance().getTickRate()) {
TickFrames++;
long nsTimeDiff = now - updateTime;
gameLogic.Update(engineInstance, nsTimeDiff / 1000000);
@ -56,12 +56,12 @@ public class PrimaryRuntime {
if (SecondCounter >= 1000000000){
SecondCounter = 0;
System.out.println("FPS: " + Frames + " Ticks: " + TickFrames);
Globals.FrameRate_PRIMARYTHREAD = Frames;
Globals.FrameRate_RENDER = Globals.RENDERFRAMES;
Globals.TPS = TickFrames;
EngineConfig.FrameRate_PRIMARYTHREAD = Frames;
EngineConfig.FrameRate_RENDER = EngineConfig.RENDERFRAMES;
EngineConfig.TPS = TickFrames;
Frames = 0;
TickFrames = 0;
Globals.RENDERFRAMES = 0;
EngineConfig.RENDERFRAMES = 0;
}
render.render(engineInstance);
FrameDiff = 0;

View file

@ -21,9 +21,9 @@ public class VulkanUtils {
return result;
}
public static void vkCheck(int err, String errMsg) {
if (err != VK_SUCCESS) {
String errCode = switch (err) {
public static void vkCheck(int Error, String ErrorMessage) {
if (Error != VK_SUCCESS) {
String ErrorCode = switch (Error) {
case VK_NOT_READY -> "VK_NOT_READY";
case VK_TIMEOUT -> "VK_TIMEOUT";
case VK_EVENT_SET -> "VK_EVENT_SET";
@ -44,7 +44,7 @@ public class VulkanUtils {
case VK_ERROR_UNKNOWN -> "VK_ERROR_UNKNOWN";
default -> "Not mapped";
};
throw new RuntimeException(errMsg + ": " + errCode + " [" + err + "]");
throw new RuntimeException(ErrorMessage + ": " + ErrorCode + " [" + Error + "]");
}
}
}