Profiling - tracks GPU and CPU usage as well as displaying performance metrics and scene information

This commit is contained in:
Halbear 2026-06-12 19:51:53 +01:00
parent c9844fc415
commit 620838a41d
22 changed files with 827 additions and 81 deletions

View file

@ -20,14 +20,12 @@ vec4 gamma(vec4 color){
return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a); return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a);
} }
vec4 msaa(int sampleCount, sampler2DMS textureIn,vec2 TextCoord){ vec4 msaa(int sampleCount, sampler2DMS textureIn,vec2 TextCoord){
ivec2 pixelCoords = ivec2(TextCoord * textureSize(textureIn)); ivec2 pixelCoords = ivec2(TextCoord * textureSize(textureIn));
vec4 colorSum = vec4(0.0); vec4 colorSum = vec4(0.0);
for(int i = 0; i < sampleCount; ++i) { for(int i = 0; i < sampleCount; ++i) {
vec4 sampleColor = texelFetch(textureIn, pixelCoords, i); vec4 sampleColor = texelFetch(textureIn, pixelCoords, i);
sampleColor.rgb = sampleColor.rgb / (sampleColor.rgb + vec3(1.0));
colorSum += sampleColor; colorSum += sampleColor;
} }
return colorSum / float(sampleCount); return colorSum / float(sampleCount);

View file

@ -21,7 +21,6 @@ vec4 gamma(vec4 color){
} }
// Sourced from: https://mini.gmshaders.com/p/gm-shaders-mini-fxaa // Sourced from: https://mini.gmshaders.com/p/gm-shaders-mini-fxaa
vec4 fxaa(sampler2D tex, vec2 uv) { vec4 fxaa(sampler2D tex, vec2 uv) {
vec2 u_texel = 1.0 / screenSize.size; vec2 u_texel = 1.0 / screenSize.size;

Binary file not shown.

View file

@ -0,0 +1,207 @@
{
"ID": "Sponza",
"Meshes": [
{
"ID": "meshes[0]-53_0",
"MaterialID": "Sponza-mat-0",
"OffsetVertex": 0,
"VertexSize": 482200,
"OffsetIndex": 0,
"IndexSize": 377232
},
{
"ID": "meshes[0]-93_1",
"MaterialID": "Sponza-mat-1",
"OffsetVertex": 482200,
"VertexSize": 78640,
"OffsetIndex": 377232,
"IndexSize": 41664
},
{
"ID": "meshes[0]-94_2",
"MaterialID": "Sponza-mat-2",
"OffsetVertex": 560840,
"VertexSize": 196800,
"OffsetIndex": 418896,
"IndexSize": 212256
},
{
"ID": "meshes[0]-99_3",
"MaterialID": "Sponza-mat-3",
"OffsetVertex": 757640,
"VertexSize": 44820,
"OffsetIndex": 631152,
"IndexSize": 49032
},
{
"ID": "meshes[0]-102_4",
"MaterialID": "Sponza-mat-4",
"OffsetVertex": 802460,
"VertexSize": 21060,
"OffsetIndex": 680184,
"IndexSize": 9552
},
{
"ID": "meshes[0]-48_5",
"MaterialID": "Sponza-mat-5",
"OffsetVertex": 823520,
"VertexSize": 193580,
"OffsetIndex": 689736,
"IndexSize": 122016
},
{
"ID": "meshes[0]-33_6",
"MaterialID": "Sponza-mat-6",
"OffsetVertex": 1017100,
"VertexSize": 99960,
"OffsetIndex": 811752,
"IndexSize": 70512
},
{
"ID": "meshes[0]-47_7",
"MaterialID": "Sponza-mat-7",
"OffsetVertex": 1117060,
"VertexSize": 62480,
"OffsetIndex": 882264,
"IndexSize": 33792
},
{
"ID": "meshes[0]-46_8",
"MaterialID": "Sponza-mat-8",
"OffsetVertex": 1179540,
"VertexSize": 460,
"OffsetIndex": 916056,
"IndexSize": 252
},
{
"ID": "meshes[0]-44_9",
"MaterialID": "Sponza-mat-9",
"OffsetVertex": 1180000,
"VertexSize": 236400,
"OffsetIndex": 916308,
"IndexSize": 85056
},
{
"ID": "meshes[0]-42_10",
"MaterialID": "Sponza-mat-10",
"OffsetVertex": 1416400,
"VertexSize": 21960,
"OffsetIndex": 1001364,
"IndexSize": 10560
},
{
"ID": "meshes[0]-49_11",
"MaterialID": "Sponza-mat-11",
"OffsetVertex": 1438360,
"VertexSize": 456400,
"OffsetIndex": 1011924,
"IndexSize": 278496
},
{
"ID": "meshes[0]-50_12",
"MaterialID": "Sponza-mat-12",
"OffsetVertex": 1894760,
"VertexSize": 720,
"OffsetIndex": 1290420,
"IndexSize": 216
},
{
"ID": "meshes[0]-62_13",
"MaterialID": "Sponza-mat-13",
"OffsetVertex": 1895480,
"VertexSize": 243240,
"OffsetIndex": 1290636,
"IndexSize": 197952
},
{
"ID": "meshes[0]-59_14",
"MaterialID": "Sponza-mat-14",
"OffsetVertex": 2138720,
"VertexSize": 182520,
"OffsetIndex": 1488588,
"IndexSize": 198144
},
{
"ID": "meshes[0]-61_15",
"MaterialID": "Sponza-mat-15",
"OffsetVertex": 2321240,
"VertexSize": 182520,
"OffsetIndex": 1686732,
"IndexSize": 198144
},
{
"ID": "meshes[0]-60_16",
"MaterialID": "Sponza-mat-16",
"OffsetVertex": 2503760,
"VertexSize": 121680,
"OffsetIndex": 1884876,
"IndexSize": 132096
},
{
"ID": "meshes[0]-72_17",
"MaterialID": "Sponza-mat-17",
"OffsetVertex": 2625440,
"VertexSize": 147960,
"OffsetIndex": 2016972,
"IndexSize": 172032
},
{
"ID": "meshes[0]-71_18",
"MaterialID": "Sponza-mat-18",
"OffsetVertex": 2773400,
"VertexSize": 198080,
"OffsetIndex": 2189004,
"IndexSize": 227328
},
{
"ID": "meshes[0]-70_19",
"MaterialID": "Sponza-mat-19",
"OffsetVertex": 2971480,
"VertexSize": 147960,
"OffsetIndex": 2416332,
"IndexSize": 172032
},
{
"ID": "meshes[0]-79_20",
"MaterialID": "Sponza-mat-20",
"OffsetVertex": 3119440,
"VertexSize": 1280,
"OffsetIndex": 2588364,
"IndexSize": 384
},
{
"ID": "meshes[0]-80_21",
"MaterialID": "Sponza-mat-21",
"OffsetVertex": 3120720,
"VertexSize": 208240,
"OffsetIndex": 2588748,
"IndexSize": 237936
},
{
"ID": "meshes[0]-95_22",
"MaterialID": "Sponza-mat-22",
"OffsetVertex": 3328960,
"VertexSize": 106160,
"OffsetIndex": 2826684,
"IndexSize": 110208
},
{
"ID": "meshes[0]-98_23",
"MaterialID": "Sponza-mat-23",
"OffsetVertex": 3435120,
"VertexSize": 34560,
"OffsetIndex": 2936892,
"IndexSize": 36504
},
{
"ID": "meshes[0]-101_24",
"MaterialID": "Sponza-mat-24",
"OffsetVertex": 3469680,
"VertexSize": 218360,
"OffsetIndex": 2973396,
"IndexSize": 173808
}
],
"VertexPath": "resources/models/Sponza/Sponza.vtx",
"IndexPath": "resources/models/Sponza/Sponza.idx"
}

Binary file not shown.

View file

@ -0,0 +1,262 @@
[
{
"ID": "Sponza-mat-0",
"TexturePath": "resources\\models\\Sponza\\5061699253647017043.png",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-1",
"TexturePath": "resources\\models\\Sponza\\8006627369776289000.png",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-2",
"TexturePath": "resources\\models\\Sponza\\7268504077753552595.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-3",
"TexturePath": "resources\\models\\Sponza\\8750083169368950601.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-4",
"TexturePath": "resources\\models\\Sponza\\5792855332885324923.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-5",
"TexturePath": "resources\\models\\Sponza\\14650633544276105767.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-6",
"TexturePath": "resources\\models\\Sponza\\15295713303328085182.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-7",
"TexturePath": "resources\\models\\Sponza\\6047387724914829168.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-8",
"TexturePath": "resources\\models\\Sponza\\5823059166183034438.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-9",
"TexturePath": "resources\\models\\Sponza\\7441062115984513793.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-10",
"TexturePath": "resources\\models\\Sponza\\11490520546946913238.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-11",
"TexturePath": "resources\\models\\Sponza\\6151467286084645207.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-12",
"TexturePath": "resources\\models\\Sponza\\white.png",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-13",
"TexturePath": "resources\\models\\Sponza\\4975155472559461469.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-14",
"TexturePath": "resources\\models\\Sponza\\4675343432951571524.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-15",
"TexturePath": "resources\\models\\Sponza\\2775690330959970771.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-16",
"TexturePath": "resources\\models\\Sponza\\2185409758123873465.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-17",
"TexturePath": "resources\\models\\Sponza\\17876391417123941155.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-18",
"TexturePath": "resources\\models\\Sponza\\11474523244911310074.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-19",
"TexturePath": "resources\\models\\Sponza\\9288698199695299068.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-20",
"TexturePath": "resources\\models\\Sponza\\16275776544635328252.png",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-21",
"TexturePath": "resources\\models\\Sponza\\755318871556304029.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-22",
"TexturePath": "resources\\models\\Sponza\\8481240838833932244.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-23",
"TexturePath": "resources\\models\\Sponza\\6772804448157695701.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-24",
"TexturePath": "resources\\models\\Sponza\\2969916736137545357.jpg",
"DiffuseColour": {
"X": 0.588,
"Y": 0.588,
"Z": 0.588,
"W": 1.0
}
},
{
"ID": "Sponza-mat-25",
"TexturePath": "",
"DiffuseColour": {
"X": 1.0,
"Y": 1.0,
"Z": 1.0,
"W": 1.0
}
}
]

View file

@ -55,6 +55,7 @@ public class Render {
public TextureCache GetTextureCache(){return textureCache;} public TextureCache GetTextureCache(){return textureCache;}
public MaterialsCache GetMaterialsCache(){return materialsCache;} public MaterialsCache GetMaterialsCache(){return materialsCache;}
public VulkanContext GetVulkanContext(){return RendererContext;}
public Render(EngineInstance engineInstance) { public Render(EngineInstance engineInstance) {
RendererContext = new VulkanContext(engineInstance.window()); RendererContext = new VulkanContext(engineInstance.window());

View file

@ -6,6 +6,8 @@ import org.tinylog.Logger;
import java.io.*; import java.io.*;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import static org.lwjgl.vulkan.VK10.*; import static org.lwjgl.vulkan.VK10.*;
@ -30,10 +32,15 @@ public class EngineConfig {
private int Width; private int Width;
private int Height; private int Height;
public static int FrameRate_PRIMARYTHREAD =0; public static int FrameRate_PRIMARYTHREAD =0;
public static int TPS_PRIMARYTHREAD =0;
public static int TPS =0; public static int TPS =0;
public static long LAST_AVERAGE_GPU_TIME = 0;
public static int FrameRate_MAINENGINETHREAD =0; public static int FrameRate_MAINENGINETHREAD =0;
public static int TPS_MAINENGINETHREAD =0;
public static int FrameRate_FASTENGINETHREAD =0; public static int FrameRate_FASTENGINETHREAD =0;
public static int TPS_FASTENGINETHREAD =0;
public static int FrameRate_RENDERTHREAD =0; public static int FrameRate_RENDERTHREAD =0;
public static int TPS_RENDERTHREAD =0;
public static int FrameRate_WINDOW =0; public static int FrameRate_WINDOW =0;
public static int RENDERFRAMES =0; public static int RENDERFRAMES =0;
public static boolean VSYNC = false; public static boolean VSYNC = false;
@ -55,7 +62,23 @@ public class EngineConfig {
private int MaxDescriptors = 1000; private int MaxDescriptors = 1000;
private int AAValue = 1; private int AAValue = 1;
private AntiAliasType AAMode = AntiAliasType.FXAA; private AntiAliasType AAMode = AntiAliasType.FXAA;
private List<String[]> MemoryProfiling = new ArrayList<>();
private List<String[]> SystemProfiling = new ArrayList<>();
public String GPU_NAME = "Vulkan compatible device";
public String CPU_NAME = "Vulkan compatible device";
public int CPU_CORE_COUNT = 0;
public String CPU_DETAILS = "";
public String GetGPU(){return GPU_NAME;}
public void SetGPU(String Gpu){GPU_NAME = Gpu;}
public void SetCPU(String Name, int CoreCount){
CPU_NAME = Name;
CPU_CORE_COUNT = CoreCount;
CPU_DETAILS = CPU_NAME + " with " + CPU_CORE_COUNT + " Threads";
}
public int GetCoreCount(){return CPU_CORE_COUNT;}
public String GetCPUName(){return CPU_NAME;}
public String GetCPUDetails(){return CPU_DETAILS;}
public void GPU_Does_Not_Support_Logging(){ public void GPU_Does_Not_Support_Logging(){
GPU_SUPPORTS_LOGGING = false; GPU_SUPPORTS_LOGGING = false;
} }
@ -63,6 +86,11 @@ public class EngineConfig {
public String GetDefaultTexturePath(){return DefaultTexturePath;} public String GetDefaultTexturePath(){return DefaultTexturePath;}
public int GetMaxDescriptors(){return MaxDescriptors;} public int GetMaxDescriptors(){return MaxDescriptors;}
public int RenderAA(){return AAValue;} public int RenderAA(){return AAValue;}
public AntiAliasType RenderAAType(){return AAMode;}
public List<String[]> GetMemoryProfiling(){return MemoryProfiling;}
public List<String[]> GetSystemProfiling(){return SystemProfiling;}
public void SetMemoryProfiling(List<String[]> memory){MemoryProfiling = memory;}
public void SetSystemProfiling(List<String[]> Profiling){SystemProfiling = Profiling;}
public enum AntiAliasType{ public enum AntiAliasType{
NONE, NONE,

View file

@ -10,4 +10,5 @@ public interface GameLogic {
void CameraInput(EngineInstance engineInstance, long FrameDiffNanoSeconds); void CameraInput(EngineInstance engineInstance, long FrameDiffNanoSeconds);
void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds); void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds);
void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds); void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds);
void SecondUpdate(EngineInstance engineInstance);
} }

View file

@ -4,6 +4,7 @@ import imgui.ImGui;
import imgui.ImGuiIO; import imgui.ImGuiIO;
import imgui.ImVec2; import imgui.ImVec2;
import imgui.flag.ImGuiCond; import imgui.flag.ImGuiCond;
import imgui.flag.ImGuiWindowFlags;
import net.halbear.Terrain4J.EngineCore.Display.Window; import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput; import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput;
import net.halbear.Terrain4J.EngineCore.Input.MouseListener; import net.halbear.Terrain4J.EngineCore.Input.MouseListener;
@ -12,6 +13,8 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.ModelLoader;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Camera; import net.halbear.Terrain4J.EngineCore.Main.Scene.Camera;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene; import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture; import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MaterialData; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MaterialData;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
@ -20,13 +23,14 @@ import org.joml.Vector3f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.UnaryOperator;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
public class GameCore implements GameLogic { public class GameCore implements GameLogic {
private static final float MOUSE_SENSITIVITY = 0.1f; private static final float MOUSE_SENSITIVITY = 0.1f;
private static final float MOVEMENT_SPEED = 0.01f; private static final float MOVEMENT_SPEED = 1f;
private final Vector3f rotatingAngle = new Vector3f(0, 1, 0); private final Vector3f rotatingAngle = new Vector3f(0, 1, 0);
private float angle = 180; private float angle = 180;
private List<Float> angles = new ArrayList<>(); private List<Float> angles = new ArrayList<>();
@ -38,6 +42,9 @@ public class GameCore implements GameLogic {
private int Ticks = 0; private int Ticks = 0;
private int GUI_MODE = 0; private int GUI_MODE = 0;
private GuiTexture guiTexture; private GuiTexture guiTexture;
private List<String[]> PerformanceMetrics = new ArrayList<>();
private List<String[]> SettingPerformanceMetrics = new ArrayList<>();
private boolean FetchingMetrics = false;
@Override @Override
public void cleanup() { public void cleanup() {
@ -49,38 +56,38 @@ public class GameCore implements GameLogic {
Scene scene = engineInstance.scene(); Scene scene = engineInstance.scene();
List<ModelData> models = new ArrayList<>(); List<ModelData> models = new ArrayList<>();
//ModelData SponzaData = ModelLoader.LoadModel("resources/models/Unit02/evangelion_unit-02.json"); //ModelData SponzaData = ModelLoader.LoadModel("resources/models/Sponza/Sponza.json");
//List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Unit02/evangelion_unit-02_mat.json"); //List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Sponza/Sponza_mat.json");
//ModelData SponzaData = ModelLoader.LoadModel("resources/models/Cafe/exterior.json"); ModelData SponzaData = ModelLoader.LoadModel("resources/models/Cafe/exterior.json");
//List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Cafe/exterior_mat.json"); List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Cafe/exterior_mat.json");
// ModelData SponzaData1 = ModelLoader.LoadModel("resources/models/Cafe/interior.json"); ModelData SponzaData1 = ModelLoader.LoadModel("resources/models/Cafe/interior.json");
// List<MaterialData> SponzaMaterial1= ModelLoader.LoadMaterials("resources/models/Cafe/interior_mat.json"); List<MaterialData> SponzaMaterial1= ModelLoader.LoadMaterials("resources/models/Cafe/interior_mat.json");
//scene.AddActor(new Actor("Sponza1", SponzaData.ID(), new Vector3f(0,0,-5f))); scene.AddActor(new Actor("Sponza1", SponzaData.ID(), new Vector3f(0,0,-5f)));
//scene.AddActor(new Actor("Sponza2", SponzaData1.ID(), new Vector3f(0,0,-5f))); scene.AddActor(new Actor("Sponza2", SponzaData1.ID(), new Vector3f(0,0,-5f)));
models.add(ModelLoader.LoadModel("resources/models/Metro/OBJ/MetroLeadCar.json")); //models.add(ModelLoader.LoadModel("resources/models/Metro/OBJ/MetroLeadCar.json"));
models.add(ModelLoader.LoadModel("resources/models/melona/melona.json")); //models.add(ModelLoader.LoadModel("resources/models/melona/melona.json"));
models.add(ModelLoader.LoadModel("resources/models/Alice/Welsh040Alice.json")); //models.add(ModelLoader.LoadModel("resources/models/Alice/Welsh040Alice.json"));
models.add(ModelLoader.LoadModel("resources/models/Sloop/SloopOBJ.json")); //models.add(ModelLoader.LoadModel("resources/models/Sloop/SloopOBJ.json"));
models.add(ModelLoader.LoadModel("resources/models/Corvette/corvetteclass.json")); //models.add(ModelLoader.LoadModel("resources/models/Corvette/corvetteclass.json"));
for(int i = 0; i < 5000; i++) { //for(int i = 0; i < 0; i++) {
CubeActors.add(new Actor("AdvancedModel" + i, models.get((int)Math.round(Math.min(Math.max(Math.random() *(Math.random() * models.size() - 1),0),models.size() - 1))).ID(), new Vector3f((float)(-200 + Math.random() * 400), (float)(-50 + Math.random() * 100), (float)(250 + Math.random() * -500)))); // CubeActors.add(new Actor("AdvancedModel" + i, models.get((int)Math.round(Math.min(Math.max(Math.random() *(Math.random() * models.size() - 1),0),models.size() - 1))).ID(), new Vector3f((float)(-200 + Math.random() * 400), (float)(-50 + Math.random() * 100), (float)(250 + Math.random() * -500))));
angles.add((float)(Math.random() * 360)); // angles.add((float)(Math.random() * 360));
rotatingAngles.add(new Vector3f((float)(Math.random()*2), (float)(Math.random()*2), (float)(Math.random()*2))); // rotatingAngles.add(new Vector3f((float)(Math.random()*2), (float)(Math.random()*2), (float)(Math.random()*2)));
Velocities.add(new Vector3f((float)(-2 + Math.random()*4), -2 + (float)(Math.random()*4), -2 + (float)(Math.random()*4))); // Velocities.add(new Vector3f((float)(-2 + Math.random()*4), -2 + (float)(Math.random()*4), -2 + (float)(Math.random()*4)));
} // }
CubeActors.forEach(scene::AddActor); CubeActors.forEach(scene::AddActor);
List<MaterialData> materials = new ArrayList<>(); List<MaterialData> materials = new ArrayList<>();
materials.addAll(ModelLoader.LoadMaterials("resources/models/Metro/OBJ/MetroLeadCar_mat.json")); //materials.addAll(ModelLoader.LoadMaterials("resources/models/Metro/OBJ/MetroLeadCar_mat.json"));
materials.addAll(ModelLoader.LoadMaterials("resources/models/Corvette/corvetteclass_mat.json")); //materials.addAll(ModelLoader.LoadMaterials("resources/models/Corvette/corvetteclass_mat.json"));
materials.addAll(ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json")); //materials.addAll(ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json"));
materials.addAll(ModelLoader.LoadMaterials("resources/models/Alice/Welsh040Alice_mat.json")); //materials.addAll(ModelLoader.LoadMaterials("resources/models/Alice/Welsh040Alice_mat.json"));
materials.addAll(ModelLoader.LoadMaterials("resources/models/Sloop/SloopOBJ_mat.json")); //materials.addAll(ModelLoader.LoadMaterials("resources/models/Sloop/SloopOBJ_mat.json"));
// materials.addAll(SponzaMaterial); materials.addAll(SponzaMaterial);
//materials.addAll(SponzaMaterial1); materials.addAll(SponzaMaterial1);
//models.add(SponzaData); models.add(SponzaData);
//models.add(SponzaData1); models.add(SponzaData1);
Camera camera = scene.GetCamera(); Camera camera = scene.GetCamera();
camera.SetPosition(40.0f, 155.0f, -42.0f); camera.SetPosition(40.0f, 155.0f, -42.0f);
camera.SetPosition(0,0,0); camera.SetPosition(0,0,0);
@ -120,7 +127,7 @@ public class GameCore implements GameLogic {
@Override @Override
public void RenderThreadInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) { public void RenderThreadInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
HandleGui(engineInstance); HandleGui(engineInstance, FrameDiffNanoSeconds);
} }
@Override @Override
@ -163,7 +170,8 @@ public class GameCore implements GameLogic {
} else camera.Sprint(false); } else camera.Sprint(false);
} }
private boolean HandleGui(EngineInstance engineInstance){ private boolean HandleGui(EngineInstance engineInstance, long frameTimeNS){
FetchingMetrics = true;
ImGuiIO imGuiIO = ImGui.getIO(); ImGuiIO imGuiIO = ImGui.getIO();
MouseListener mouseListener = engineInstance.window().getMouseInput(); MouseListener mouseListener = engineInstance.window().getMouseInput();
Vector2f mousePosition = mouseListener.getCurrentPos(); Vector2f mousePosition = mouseListener.getCurrentPos();
@ -172,8 +180,38 @@ public class GameCore implements GameLogic {
imGuiIO.addMouseButtonEvent(1,mouseListener.isRightButtonPressed()); imGuiIO.addMouseButtonEvent(1,mouseListener.isRightButtonPressed());
if(GUI_MODE == 0){ if(GUI_MODE == 0){
double FrameTimeMS = (frameTimeNS/1000000.0);
double AverageGPUTimeMS = EngineConfig.LAST_AVERAGE_GPU_TIME/1000000.0;
int windowFlags = ImGuiWindowFlags.NoDecoration
| ImGuiWindowFlags.AlwaysAutoResize
| ImGuiWindowFlags.NoSavedSettings
| ImGuiWindowFlags.NoFocusOnAppearing
| ImGuiWindowFlags.NoNav
| ImGuiWindowFlags.NoMove;
ImGui.newFrame(); ImGui.newFrame();
ImGui.showDemoWindow(); ImGui.setNextWindowPos(0,0, ImGuiCond.Always);
//ImGui.setNextWindowSize(300,100);
ImGui.begin("FPS overlay",windowFlags);
ImGui.text("PERFORMANCE METRICS:");
ImGui.separator();
ImGui.text(String.format("Vulkan FPS: " + EngineConfig.FrameRate_RENDERTHREAD + "fps | FrameTime: %.2f" + "ms | Avg. GPU Time: %.3f" + "ms | TPS: " + EngineConfig.TPS_RENDERTHREAD,FrameTimeMS,AverageGPUTimeMS));
ImGui.text(String.format("Primary Thread FPS: " + EngineConfig.FrameRate_PRIMARYTHREAD + "fps | GLFW Window FrameRate:" + EngineConfig.FrameRate_WINDOW + "fps | TPS: " + EngineConfig.TPS_PRIMARYTHREAD));
ImGui.text(String.format("Main Thread FPS: " + EngineConfig.FrameRate_MAINENGINETHREAD + "fps | TPS: " + EngineConfig.TPS_MAINENGINETHREAD));
ImGui.text(String.format("Fast Thread FPS: " + EngineConfig.FrameRate_FASTENGINETHREAD + "fps | TPS: " + EngineConfig.TPS_FASTENGINETHREAD));
if(PerformanceMetrics.size() > 0) {
ImGui.text(" ");
ImGui.separator();
for (int i = 0; i < PerformanceMetrics.size(); i++) {
String[] memoryUsageMetrics = PerformanceMetrics.get(i);
for(int j = 0; j < memoryUsageMetrics.length; j++){
ImGui.text(memoryUsageMetrics[j]);
}
ImGui.separator();
ImGui.text(" ");
}
}
ImGui.end();
ImGui.endFrame(); ImGui.endFrame();
ImGui.render(); ImGui.render();
} else if (GUI_MODE == 1){ } else if (GUI_MODE == 1){
@ -190,6 +228,7 @@ public class GameCore implements GameLogic {
ImGui.endFrame(); ImGui.endFrame();
ImGui.render(); ImGui.render();
} }
FetchingMetrics = false;
return imGuiIO.getWantCaptureKeyboard(); return imGuiIO.getWantCaptureKeyboard();
} }
@ -218,4 +257,30 @@ public class GameCore implements GameLogic {
CubeActors.get(i).UpdateModelMatrix(); CubeActors.get(i).UpdateModelMatrix();
} }
} }
@Override
public void SecondUpdate(EngineInstance engineInstance) {
SettingPerformanceMetrics.clear();
List<String[]> Metrics = new ArrayList<>();
String[] SceneDetails = new String[5];
Vector3f Position = engineInstance.scene().GetCamera().GetPosition();
Vector3f Rotation = engineInstance.scene().GetCamera().GetRotation();
SceneDetails[0] = String.format("INSTANCE INFORMATION: ");
SceneDetails[1] = String.format(" Camera Position: X: %.2f Y: %.2f Z: %.2f",Position.x ,Position.y ,Position.z);
SceneDetails[2] = String.format(" Camera Rotation: X: %.2f° Y: %.2f° Z: %.2f°",Rotation.x *EngineConfig.RadToDeg,Rotation.y *EngineConfig.RadToDeg ,Rotation.z *EngineConfig.RadToDeg);
SceneDetails[3] = String.format(" Anti Aliasing: " + EngineConfig.getInstance().RenderAAType().name());
SceneDetails[4] = String.format(" FOV: %.2f°",(EngineConfig.getInstance().GetFOV()*EngineConfig.RadToDeg));
String[] DeviceInfo = new String[5];
DeviceInfo[0] = String.format("SYSTEM INFORMATION: ");
DeviceInfo[1] = String.format(" CPU: " + EngineConfig.getInstance().GetCPUDetails());
DeviceInfo[2] = String.format(" RAM: " + CPUMonitor.RamSize);
DeviceInfo[3] = String.format(" GPU: " + EngineConfig.getInstance().GetGPU());
DeviceInfo[4] = String.format(" VRAM: " + GPUProfiler.GetVramCapacity());
Metrics.add(SceneDetails);
Metrics.add(DeviceInfo);
SettingPerformanceMetrics.addAll(Metrics);
SettingPerformanceMetrics.addAll(EngineConfig.getInstance().GetMemoryProfiling());
SettingPerformanceMetrics.addAll(EngineConfig.getInstance().GetSystemProfiling());
PerformanceMetrics = List.copyOf(SettingPerformanceMetrics);
}
} }

View file

@ -34,6 +34,8 @@ public class PrimaryRuntime {
public final CPUMonitor cpuProfiler; public final CPUMonitor cpuProfiler;
private static GameLogic gameLogic; private static GameLogic gameLogic;
public static GameLogic GetGameCore(){return gameLogic;}
public PrimaryRuntime(String windowTitle, GameLogic appLogic) { public PrimaryRuntime(String windowTitle, GameLogic appLogic) {
String[] knownDLSSfiles = {"nvngx_dlss.dll", "nvngx_dlssg.dll", "_nvngx.dll"}; String[] knownDLSSfiles = {"nvngx_dlss.dll", "nvngx_dlssg.dll", "_nvngx.dll"};
for (String dllName : knownDLSSfiles) { for (String dllName : knownDLSSfiles) {
@ -57,6 +59,7 @@ public class PrimaryRuntime {
FastThread = new FastTickThread(engineInstance, appLogic); FastThread = new FastTickThread(engineInstance, appLogic);
DrawingThread = new RenderThread(window, engineInstance, initData, appLogic); DrawingThread = new RenderThread(window, engineInstance, initData, appLogic);
cpuProfiler = new CPUMonitor(); cpuProfiler = new CPUMonitor();
EngineConfig.getInstance().SetCPU(CPUMonitor.getCpuName(), CPUMonitor.getCoreCount());
Thread.currentThread().setName("Terrain4J Primary Runtime Thread"); Thread.currentThread().setName("Terrain4J Primary Runtime Thread");
} }
public static MainThread GetMainThread(){return PrimaryThread;} public static MainThread GetMainThread(){return PrimaryThread;}
@ -121,8 +124,7 @@ public class PrimaryRuntime {
SecondCounter = 0; SecondCounter = 0;
EngineConfig.FrameRate_WINDOW = EngineConfig.RENDERFRAMES; EngineConfig.FrameRate_WINDOW = EngineConfig.RENDERFRAMES;
EngineConfig.FrameRate_PRIMARYTHREAD = Frames; EngineConfig.FrameRate_PRIMARYTHREAD = Frames;
EngineConfig.TPS = TickFrames; EngineConfig.TPS_PRIMARYTHREAD = TickFrames;
Logger.info("Primary Thread FPS: " + Frames + " TPS: " + TickFrames + " Window Draw FPS: " + EngineConfig.RENDERFRAMES);
Frames = 0; Frames = 0;
TickFrames = 0; TickFrames = 0;
EngineConfig.RENDERFRAMES = 0; EngineConfig.RENDERFRAMES = 0;

View file

@ -1,19 +1,102 @@
package net.halbear.Terrain4J.EngineCore.Profiling; package net.halbear.Terrain4J.EngineCore.Profiling;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean; import com.sun.management.OperatingSystemMXBean;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class CPUMonitor { public class CPUMonitor {
private final OperatingSystemMXBean OSBean; private final OperatingSystemMXBean OSBean;
public static String RamSize = "0.0GB";
public CPUMonitor(){ public CPUMonitor(){
OSBean = ManagementFactory.getOperatingSystemMXBean(); OSBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
} }
public String LogCPUUsage(){ public static String GetRamSize(){return RamSize;}
return "";
public static String[] LogCPUUsage(){
OperatingSystemMXBean OSBean= (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
double processCPU = OSBean.getProcessCpuLoad();
double SystemCPU = OSBean.getCpuLoad();
long totalPhysicalMemory = OSBean.getTotalPhysicalMemorySize();
long freePhysicalMemory = OSBean.getFreePhysicalMemorySize();
long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory;
RamSize = String.format("%.2f" + "gb",ConvertToGB(totalPhysicalMemory));
Runtime runtime = Runtime.getRuntime();
long maxHeap = runtime.maxMemory();
long totalHeap = runtime.totalMemory();
long freeHeap = runtime.freeMemory();
long usedHeap = totalHeap - freeHeap;
int TotalCores = Runtime.getRuntime().availableProcessors();
double ActiveSystemCores = TotalCores * SystemCPU;
double ActiveProcessCores = TotalCores * processCPU;
String[] CPUMetrics = new String[6];
CPUMetrics[0] = String.format("CPU & SYSTEM MEMORY USAGE:\n");
CPUMetrics[1] = String.format(" Terrain4J CPU Core Usage: %d / %d", (int)Math.ceil(ActiveProcessCores),TotalCores);
CPUMetrics[2] = String.format(" Terrain4J CPU Usage: %.2f%%%n", processCPU * 100);
CPUMetrics[3] = String.format(" Terrain4J Memory Usage: %d MB / %d MB%n", ConvertToMB(usedHeap), ConvertToMB(maxHeap));
CPUMetrics[4] = String.format(" Total CPU Load: %.2f%%%n", SystemCPU * 100);
CPUMetrics[5] = String.format(" System Memory Used: %d MB / %d MB%n", ConvertToMB(usedPhysicalMemory), ConvertToMB(totalPhysicalMemory));
return CPUMetrics;
}
public static List<String> GetThreadsInUse(){
List<String> Threads = new ArrayList<>();
Thread.getAllStackTraces().keySet().forEach(thread ->
{
Threads.add(thread.getName());
});
return Threads;
}
private static double ConvertToGB(long bytes) {
return (double)(bytes / (1024 * 1024* 1024));
}
private static long ConvertToMB(long bytes) {
return bytes / (1024 * 1024);
}
public static int getCoreCount(){
return Runtime.getRuntime().availableProcessors();
}
public static String getCpuName() {
String os = System.getProperty("os.name").toLowerCase();
String command = "";
if (os.contains("win")) {
command = "wmic cpu get name";
} else if (os.contains("mac")) {
command = "sysctl -n machdep.cpu.brand_string";
} else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) {
command = "sh -c lscpu | grep 'Model name:'";
} else {
return "Unknown OS - Cannot fetch CPU name";
}
try {
Process process = Runtime.getRuntime().exec(command);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
StringBuilder output = new StringBuilder();
while ((line = reader.readLine()) != null) {
if (!line.trim().isEmpty() && !line.toLowerCase().contains("name")) {
output.append(line.trim());
break;
}
}
return output.toString().isEmpty() ? "Unknown CPU" : output.toString();
}
} catch (Exception e) {
return "Error reading CPU name: " + e.getMessage();
}
} }
} }

View file

@ -1,17 +1,56 @@
package net.halbear.Terrain4J.EngineCore.Profiling; package net.halbear.Terrain4J.EngineCore.Profiling;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer; import org.lwjgl.vulkan.*;
import org.lwjgl.vulkan.VkDevice;
import org.lwjgl.vulkan.VkQueryPoolCreateInfo;
import java.nio.LongBuffer; import java.nio.LongBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.vulkan.EXTMemoryBudget.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
import static org.lwjgl.vulkan.VK13.*; import static org.lwjgl.vulkan.VK13.*;
public class GPUProfiler { public class GPUProfiler {
private static String VramCapacity = "";
public static String GetVramCapacity(){return VramCapacity;}
public static List<String[]> GetVramUsage(VkPhysicalDevice physicalDevice){
List<String[]> result = new ArrayList<>();
try(var MemStack = MemoryStack.stackPush()){
VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget =
VkPhysicalDeviceMemoryBudgetPropertiesEXT.calloc(MemStack)
.sType(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT);
VkPhysicalDeviceMemoryProperties2 MemoryProperties2 = VkPhysicalDeviceMemoryProperties2.calloc(MemStack)
.sType(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2)
.pNext(memoryBudget.address());
vkGetPhysicalDeviceMemoryProperties2(physicalDevice,MemoryProperties2);
VkPhysicalDeviceMemoryProperties MemoryProperties = MemoryProperties2.memoryProperties();
int HeapCount = MemoryProperties.memoryHeapCount();
for(int i = 0; i < HeapCount; i++){
VkMemoryHeap heap = MemoryProperties.memoryHeaps(i);
if ((heap.flags() & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) {
long AllocatedByProcess = memoryBudget.heapUsage(i);
long OverallSystemBudget = memoryBudget.heapBudget(i);
long TotalHeapSize = heap.size();
String[] properties = new String[5];
VramCapacity = String.format(" %.2f GB\n",TotalHeapSize / (1024.0 * 1024.0*1024.0));
properties[0] = String.format("VIDEO MEMORY USAGE METRICS:\n");
properties[1] = String.format("VRAM Heap %d :", i);
properties[2] = String.format(" Total Capacity: %.2f MB\n", TotalHeapSize / (1024.0 * 1024.0));
properties[3] = String.format(" Terrain4J Usage: %.2f MB\n", AllocatedByProcess / (1024.0 * 1024.0));
properties[4] = String.format(" System Budget: %.2f MB\n", OverallSystemBudget / (1024.0 * 1024.0));
result.add(properties);
}
}
}
return result;
}
private long RemoteryInstance; private long RemoteryInstance;
public GPUProfiler(){ public GPUProfiler(){

View file

@ -83,6 +83,7 @@ public class EngineThread implements Runnable{
FrameTimes[1] += FrameTimes[0]; FrameTimes[1] += FrameTimes[0];
FrameTimes[2] += FrameTimes[0]; FrameTimes[2] += FrameTimes[0];
FrameTimes[3] += FrameTimes[0]; FrameTimes[3] += FrameTimes[0];
CycleEvent();
if (FrameTimes[1] >= EngineAccuracy){ if (FrameTimes[1] >= EngineAccuracy){
FrameEvent(now, InitialTime); FrameEvent(now, InitialTime);
Frames++; Frames++;

View file

@ -29,7 +29,7 @@ public class FastTickThread extends EngineThread {
@Override @Override
public void SecondEvent(){ public void SecondEvent(){
EngineConfig.FrameRate_FASTENGINETHREAD = Frames; EngineConfig.FrameRate_FASTENGINETHREAD = Frames;
Logger.info(ThreadName + " Thread FPS: " + EngineConfig.FrameRate_FASTENGINETHREAD + " TPS: " + TickFrames); EngineConfig.TPS_FASTENGINETHREAD = TickFrames;
} }
public void UpdateTickRateThreshold(){ public void UpdateTickRateThreshold(){

View file

@ -4,8 +4,13 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic; import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MainThread extends EngineThread { public class MainThread extends EngineThread {
@Override @Override
@ -14,6 +19,7 @@ public class MainThread extends EngineThread {
} }
@Override @Override
public void FrameEvent(long now, long InitialTime){ public void FrameEvent(long now, long InitialTime){
gameLogic.Update(PrimaryRuntime.GetEngineInstance(), (now - InitialTime));
} }
@Override @Override
public void CycleEvent(){ public void CycleEvent(){
@ -22,7 +28,24 @@ public class MainThread extends EngineThread {
@Override @Override
public void SecondEvent(){ public void SecondEvent(){
EngineConfig.FrameRate_MAINENGINETHREAD = Frames; EngineConfig.FrameRate_MAINENGINETHREAD = Frames;
Logger.info(ThreadName + " Thread FPS: " + EngineConfig.FrameRate_MAINENGINETHREAD + " TPS: " + TickFrames); EngineConfig.TPS_MAINENGINETHREAD = TickFrames;
List<String[]> profiling = new ArrayList<>();
profiling.addAll(Collections.singleton(CPUMonitor.LogCPUUsage()));
List<String> Threads = CPUMonitor.GetThreadsInUse();
String[] ThreadInformation = new String[Math.min(Threads.size() + 3,14)];
ThreadInformation[0] = "\nTERRAIN4J PROCESS INFORMATION:\n";
ThreadInformation[1] = String.format("Thread Count: %d \n",Threads.size());
ThreadInformation[2] = "v Threads In Use v\n";
for(int i = 0; i < Math.min(Threads.size(),10); i++){
ThreadInformation[3 + i] = String.format("Thread %d -> %s",i,Threads.get(i));
}
if(Threads.size() > 10){
ThreadInformation[13] = "...";
}
profiling.addAll(Collections.singleton(ThreadInformation));
EngineConfig.getInstance().SetSystemProfiling(profiling);
gameLogic.SecondUpdate(PrimaryRuntime.GetEngineInstance());
} }
public void UpdateTickRateThreshold(){ public void UpdateTickRateThreshold(){
CappedToTickRate = EngineConfig.getInstance().GetMainTickCap(); CappedToTickRate = EngineConfig.getInstance().GetMainTickCap();

View file

@ -5,8 +5,15 @@ import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Logic.*; import net.halbear.Terrain4J.EngineCore.Logic.*;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.SceneRender;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RenderThread extends EngineThread { public class RenderThread extends EngineThread {
private final Render render; private final Render render;
private Window window; private Window window;
@ -26,16 +33,21 @@ public class RenderThread extends EngineThread {
@Override @Override
public void FrameEvent(long now, long InitialTime){ public void FrameEvent(long now, long InitialTime){
gameLogic.RenderThreadInput(PrimaryRuntime.GetEngineInstance(), (now-InitialTime)); gameLogic.RenderThreadInput(PrimaryRuntime.GetEngineInstance(), (now-InitialTime));
gameLogic.Update(PrimaryRuntime.GetEngineInstance(), (now - InitialTime));
render.render(PrimaryRuntime.GetEngineInstance()); render.render(PrimaryRuntime.GetEngineInstance());
} }
@Override @Override
public void CycleEvent(){ public void CycleEvent(){
} }
@Override @Override
public void SecondEvent(){ public void SecondEvent(){
Logger.info("Render FPS: " + Frames); EngineConfig.LAST_AVERAGE_GPU_TIME = SceneRender.GetGPUTimeNS();
List<String[]> Profiling =GPUProfiler.GetVramUsage(render.GetVulkanContext().GetPhysicalDevice().GetPhysicalDevice());
EngineConfig.getInstance().SetMemoryProfiling(Profiling);
EngineConfig.FrameRate_RENDERTHREAD = Frames;
EngineConfig.TPS_RENDERTHREAD = TickFrames;
} }

View file

@ -20,47 +20,37 @@ import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_SRGB;
public class TextureCache { public class TextureCache {
public static final int MAX_TEXTURES = 500; public static final int MAX_TEXTURES = 500;
private final IndexedLinkedHashMap<String, Texture> TextureMap; private final IndexedLinkedHashMap<String, Texture> TextureMap;
private final IndexedLinkedHashMap<String, Texture> UnpaddedTextureMap; private final List<String> ActualTextures;
public TextureCache(){ public TextureCache(){
TextureMap = new IndexedLinkedHashMap<>(); TextureMap = new IndexedLinkedHashMap<>();
UnpaddedTextureMap = new IndexedLinkedHashMap<>(); ActualTextures = new ArrayList<>();
} }
public Texture AddToMainMap(VulkanContext VkCtx, String ID, String TexturePath, int Format) { public Texture AddTexture(VulkanContext VkCtx, String ID, ImageSrc imageSrc, int Format) {
ImageSrc imageSrc = null; return AddTexture(VkCtx,ID,imageSrc,Format,false);
Texture result = null;
try{
imageSrc = GraphUtils.LoadImage(TexturePath);
result = AddTexture(VkCtx, ID, imageSrc, Format);
} catch (IOException exception){
Logger.error("Could not load texture from patch [{}], exception: {}",TexturePath, exception);
} finally{
if(imageSrc != null){
GraphUtils.CleanImageData(imageSrc);
} }
} public Texture AddTexture(VulkanContext VkCtx, String ID, ImageSrc imageSrc, int Format, boolean PaddingTexture){
return result;
}
public Texture AddTexture(VulkanContext VkCtx, String ID, ImageSrc imageSrc, int Format){
if(TextureMap.size() > MAX_TEXTURES){ if(TextureMap.size() > MAX_TEXTURES){
throw new IllegalArgumentException("Texture Cache Is Full"); throw new IllegalArgumentException("Texture Cache Is Full");
} }
Texture newTexture = UnpaddedTextureMap.get(ID); Texture newTexture = TextureMap.get(ID);
if(newTexture == null){ if(newTexture == null){
newTexture = new Texture(VkCtx, ID, imageSrc, Format); newTexture = new Texture(VkCtx, ID, imageSrc, Format);
UnpaddedTextureMap.put(ID, newTexture); if(!PaddingTexture)ActualTextures.add(ID);
TextureMap.put(ID, newTexture); TextureMap.put(ID, newTexture);
} }
return newTexture; return newTexture;
} }
public Texture AddTexture(VulkanContext VkCtx, String ID, String TexturePath, int Format) { public Texture AddTexture(VulkanContext VkCtx, String ID, String TexturePath, int Format) {
return AddTexture(VkCtx,ID,TexturePath,Format,false);
}
public Texture AddTexture(VulkanContext VkCtx, String ID, String TexturePath, int Format, boolean PaddingTexture) {
ImageSrc imageSrc = null; ImageSrc imageSrc = null;
Texture result = null; Texture result = null;
try{ try{
imageSrc = GraphUtils.LoadImage(TexturePath); imageSrc = GraphUtils.LoadImage(TexturePath);
result = AddTexture(VkCtx, ID, imageSrc, Format); result = AddTexture(VkCtx, ID, imageSrc, Format,PaddingTexture);
} catch (IOException exception){ } catch (IOException exception){
Logger.error("Could not load texture from patch [{}], exception: {}",TexturePath, exception); Logger.error("Could not load texture from patch [{}], exception: {}",TexturePath, exception);
} finally{ } finally{
@ -73,14 +63,21 @@ public class TextureCache {
public void TransitionTexts(VulkanContext VkCtx, CommandPool CmdPool, Queue queue){ public void TransitionTexts(VulkanContext VkCtx, CommandPool CmdPool, Queue queue){
Logger.debug("Recording Texture Transition"); Logger.debug("Recording Texture Transition");
IndexedLinkedHashMap<String, Texture> NewTextureMap = new IndexedLinkedHashMap<>();
TextureMap.forEach((name,texture)->{
if(ActualTextures.contains(name)){
NewTextureMap.put(name,texture);
}
});
TextureMap.clear(); TextureMap.clear();
TextureMap.putAll(UnpaddedTextureMap); TextureMap.putAll(NewTextureMap);
NewTextureMap.clear();
int TextureCount = TextureMap.size(); int TextureCount = TextureMap.size();
if(TextureCount < MAX_TEXTURES){ if(TextureCount < MAX_TEXTURES){
int PaddingTextCount = MAX_TEXTURES - TextureCount; int PaddingTextCount = MAX_TEXTURES - TextureCount;
String DefaultTexturePath = EngineConfig.getInstance().GetDefaultTexturePath(); String DefaultTexturePath = EngineConfig.getInstance().GetDefaultTexturePath();
for(int i = 0; i < PaddingTextCount; i++){ for(int i = 0; i < PaddingTextCount; i++){
AddToMainMap(VkCtx, UUID.randomUUID().toString(), DefaultTexturePath, VK_FORMAT_R8G8B8A8_SRGB); AddTexture(VkCtx, UUID.randomUUID().toString(), DefaultTexturePath, VK_FORMAT_R8G8B8A8_SRGB,true);
} }
} }
var CommandBuffer = new CommandBuffer(VkCtx, CmdPool, true, true); var CommandBuffer = new CommandBuffer(VkCtx, CmdPool, true, true);

View file

@ -1,5 +1,6 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers; package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.VulkanInstance; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.VulkanInstance;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
@ -13,6 +14,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck; import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.EXTMemoryBudget.VK_EXT_MEMORY_BUDGET_EXTENSION_NAME;
import static org.lwjgl.vulkan.VK13.*; import static org.lwjgl.vulkan.VK13.*;
public class PhysicalDevice { public class PhysicalDevice {
@ -28,6 +30,7 @@ public class PhysicalDevice {
static{ static{
REQUIRED_EXTENSIONS = new HashSet<>(); REQUIRED_EXTENSIONS = new HashSet<>();
REQUIRED_EXTENSIONS.add(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME); REQUIRED_EXTENSIONS.add(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME);
REQUIRED_EXTENSIONS.add(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
} }
private PhysicalDevice(VkPhysicalDevice VulkanPhysicalDevice){ private PhysicalDevice(VkPhysicalDevice VulkanPhysicalDevice){
@ -92,6 +95,7 @@ public class PhysicalDevice {
if (result == null){ if (result == null){
throw new RuntimeException("No Graphics Driver Found!"); throw new RuntimeException("No Graphics Driver Found!");
} }
EngineConfig.getInstance().SetGPU(result.FetchDeviceName());
Logger.debug("Selected Graphics Driver: [{}]", result.FetchDeviceName()); Logger.debug("Selected Graphics Driver: [{}]", result.FetchDeviceName());
} }
return result; return result;

View file

@ -51,7 +51,7 @@ public class SceneRender implements SceneRenderer {//dynamic rendering
private final TextureSampler textureSampler; private final TextureSampler textureSampler;
private static final int COLOUR_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; private static final int COLOUR_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
private static final int DEPTH_FORMAT = VK_FORMAT_D16_UNORM; private static final int DEPTH_FORMAT = VK_FORMAT_D32_SFLOAT_S8_UINT;
private final VkClearValue ClearValueDepth; private final VkClearValue ClearValueDepth;
private final ByteBuffer PushConstBuffer; private final ByteBuffer PushConstBuffer;
private Attachment AttachmentDepth; private Attachment AttachmentDepth;
@ -68,6 +68,8 @@ public class SceneRender implements SceneRenderer {//dynamic rendering
private boolean Bb = false; private boolean Bb = false;
public int Frames = 0; public int Frames = 0;
private static String LastGPULog = ""; private static String LastGPULog = "";
public static long GPUTIME = 0;
public static long CYCLES = 0;
private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_fragment.glsl"; private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_fragment.glsl";
private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv"; private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv";
@ -77,9 +79,19 @@ public class SceneRender implements SceneRenderer {//dynamic rendering
private final Pipeline VkPipeline; private final Pipeline VkPipeline;
private Matrix4f ProjectionMatrix; private Matrix4f ProjectionMatrix;
public static long GetGPUTimeNS(){
long time = 0;
if(CYCLES > 0){
time = GPUTIME/CYCLES;
}
GPUTIME = 0;
CYCLES = 0;
return time;
}
public SceneRender(VulkanContext vulkanContext){ public SceneRender(VulkanContext vulkanContext){
ClearValueColour = VkClearValue.calloc().color( ClearValueColour = VkClearValue.calloc().color(
c -> c.float32(0, R).float32(1, G).float32(2, B).float32(3, 0.0f)); c -> c.float32(0, R).float32(1, G).float32(2, B).float32(3, 1.0f));
ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 0.0f)); ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 0.0f));
AttachmentColour = CreateColourAttachment(vulkanContext); AttachmentColour = CreateColourAttachment(vulkanContext);
AttachmentDepth = CreateDepthAttachment(vulkanContext); AttachmentDepth = CreateDepthAttachment(vulkanContext);
@ -222,6 +234,7 @@ public class SceneRender implements SceneRenderer {//dynamic rendering
VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_DEPTH_BIT); VK_IMAGE_ASPECT_DEPTH_BIT);
long InitialTime = System.nanoTime();
vkCmdBeginRendering(CommandHandle, RenderInfo); vkCmdBeginRendering(CommandHandle, RenderInfo);
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipeline()); vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipeline());
@ -255,6 +268,8 @@ public class SceneRender implements SceneRenderer {//dynamic rendering
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, true); RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, true);
vkCmdEndRendering(CommandHandle); vkCmdEndRendering(CommandHandle);
GPUTIME += System.nanoTime() - InitialTime;
CYCLES++;
} }
} }

View file

@ -11,16 +11,23 @@ display_width=640
#the precision of frames, set this to 16000000, 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 frame_accuracy=0
throttle_on_unfocus=true throttle_on_unfocus=true
throttle_accuracy=500000000 throttle_accuracy=100000000
#event tick rate for game process #event tick rate for game process
master_tick_rate=120 master_tick_rate=240
main_thread_tickrate=120 main_thread_tickrate=120
fast_thread_tickrate=240 fast_thread_tickrate=240
cap_master_to_tickrate=false cap_master_to_tickrate=true
cap_main_to_tickrate=true cap_main_to_tickrate=true
cap_fast_to_tickrate=true cap_fast_to_tickrate=true
#Renderer Properties #Renderer Properties
#AA settings
#0=No AA
#1=FXAA
#2=MSAAx2
#3=MSAAx4
#4=MSAAx8
anti_alias_mode=0
Debug_Shaders = false Debug_Shaders = false
ShaderRecompiling = true ShaderRecompiling = true
#Vulkan Debugging toggle #Vulkan Debugging toggle
@ -34,5 +41,7 @@ PhysicalDeviceName=
#3D Projection Properties #3D Projection Properties
field_of_view=60.0f field_of_view=60.0f
z_near_plane=1.0f z_far_plane=0.1f
z_far_plane=100.0f z_near_plane=10000.0f

View file

@ -11,7 +11,7 @@ display_width=640
#the precision of frames, set this to 16000000, 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 frame_accuracy=0
throttle_on_unfocus=true throttle_on_unfocus=true
throttle_accuracy=500000000 throttle_accuracy=100000000
#event tick rate for game process #event tick rate for game process
master_tick_rate=240 master_tick_rate=240
main_thread_tickrate=120 main_thread_tickrate=120
@ -27,7 +27,7 @@ cap_fast_to_tickrate=true
#2=MSAAx2 #2=MSAAx2
#3=MSAAx4 #3=MSAAx4
#4=MSAAx8 #4=MSAAx8
anti_alias_mode=0 anti_alias_mode=4
Debug_Shaders = false Debug_Shaders = false
ShaderRecompiling = true ShaderRecompiling = true
#Vulkan Debugging toggle #Vulkan Debugging toggle
@ -41,7 +41,7 @@ PhysicalDeviceName=
#3D Projection Properties #3D Projection Properties
field_of_view=60.0f field_of_view=60.0f
z_far_plane=1f z_far_plane=0.1f
z_near_plane=10000.0f z_near_plane=10000.0f