ClientDrawCellManager optimizations
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-11-10 14:51:29 -05:00
parent 221bcd70a7
commit 4d6db78059
21 changed files with 272 additions and 81 deletions

7
.gitignore vendored
View File

@ -62,4 +62,9 @@
*/~$*.xlsx */~$*.xlsx
#General cache for the engine #General cache for the engine
/.cache /.cache
#Memory debug files
/heap.dump
/heap.dump.hwcache
/tmp

9
.vscode/launch.json vendored
View File

@ -8,14 +8,15 @@
"type": "java", "type": "java",
"name": "Launch Current File", "name": "Launch Current File",
"request": "launch", "request": "launch",
"mainClass": "${file}" "mainClass": "${file}",
"vmArgs": "-Xmx4G -Xms1024m -XX:+UseZGC -XX:SoftMaxHeapSize=3G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"./tmp/heap.dump\""
}, },
{ {
"type": "java", "type": "java",
"name": "Launch Main", "name": "Launch Main",
"request": "launch", "request": "launch",
"mainClass": "electrosphere.engine.Main", "mainClass": "electrosphere.engine.Main",
"vmArgs": "-Xmx2G -Xms100m -XX:+UseZGC -XX:+UseDynamicNumberOfGCThreads -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"/tmp\"", "vmArgs": "-Xmx4G -Xms1024m -XX:+UseZGC -XX:SoftMaxHeapSize=3G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"./tmp/heap.dump\"",
"projectName": "Renderer" "projectName": "Renderer"
}, },
{ {
@ -23,7 +24,7 @@
"name": "Launch Main (Debug Memory)", "name": "Launch Main (Debug Memory)",
"request": "launch", "request": "launch",
"mainClass": "electrosphere.engine.Main", "mainClass": "electrosphere.engine.Main",
"vmArgs": "-Xmx2G -Xms100m -XX:+UseZGC -XX:+UseDynamicNumberOfGCThreads -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"/tmp\" -javaagent:./lwjglx-debug-1.0.0.jar=t;o=trace.log", "vmArgs": "-Xmx4G -Xms1024m -XX:+UseZGC -XX:SoftMaxHeapSize=3G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"./tmp/heap.dump\" -javaagent:./lwjglx-debug-1.0.0.jar=t;o=trace.log",
"projectName": "Renderer" "projectName": "Renderer"
}, },
{ {
@ -34,7 +35,7 @@
"env": { "env": {
"ALSOFT_LOGLEVEL": 4, "ALSOFT_LOGLEVEL": 4,
}, },
"vmArgs": "-Xmx2G -Xms100m -XX:+UseZGC -XX:+UseDynamicNumberOfGCThreads -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"/tmp\"", "vmArgs": "-Xmx4G -Xms1024m -XX:+UseZGC -XX:SoftMaxHeapSize=3G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"./tmp/heap.dump\"",
"projectName": "Renderer" "projectName": "Renderer"
}, },
{ {

View File

@ -973,6 +973,10 @@ ScriptEngine full re-initialization signal
Add surface width to test generator Add surface width to test generator
User setting to toggle foliage manager User setting to toggle foliage manager
Fix client terrain cache lookup bug Fix client terrain cache lookup bug
Memory debugging work + update memory flags in launch file
(11/10/2024)
Attempts at optimizing ClientDrawCellManager
# TODO # TODO

View File

@ -122,7 +122,7 @@ public class ClientSceneWrapper {
* @param clientEntity The client entity * @param clientEntity The client entity
*/ */
public void deregisterTranslationMapping(Entity clientEntity){ public void deregisterTranslationMapping(Entity clientEntity){
if(clientToServerMapContainsId(clientEntity.getId())){ if(this.clientToServerMapContainsId(clientEntity.getId())){
//remove from client->server map //remove from client->server map
int serverId = clientToServerIdMap.remove(clientEntity.getId()); int serverId = clientToServerIdMap.remove(clientEntity.getId());
//remove from server->client map //remove from server->client map

View File

@ -17,6 +17,11 @@ public class ChunkData {
*/ */
public static final int NO_STRIDE = 0; public static final int NO_STRIDE = 0;
/**
* The id for a non-homogenous data
*/
public static final int NOT_HOMOGENOUS = -1;
//The size of a chunk in virtual data //The size of a chunk in virtual data
public static final int CHUNK_SIZE = ServerTerrainChunk.CHUNK_DIMENSION; public static final int CHUNK_SIZE = ServerTerrainChunk.CHUNK_DIMENSION;
//The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk //The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk
@ -35,10 +40,12 @@ public class ChunkData {
* The word x coordinate * The word x coordinate
*/ */
int worldX; int worldX;
/** /**
* The word y coordinate * The word y coordinate
*/ */
int worldY; int worldY;
/** /**
* The word z coordinate * The word z coordinate
*/ */
@ -49,18 +56,25 @@ public class ChunkData {
*/ */
int stride; int stride;
/**
* Tracks whether this chunk is homogenous or not
*/
int homogenousValue = NOT_HOMOGENOUS;
/** /**
* Creates a chunk data * Creates a chunk data
* @param worldX The word x coordinate * @param worldX The word x coordinate
* @param worldY The word y coordinate * @param worldY The word y coordinate
* @param worldZ The word z coordinate * @param worldZ The word z coordinate
* @param stride The stride of the data * @param stride The stride of the data
* @param homogenous Tracks whether this chunk is homogenous or not
*/ */
public ChunkData(int worldX, int worldY, int worldZ, int stride){ public ChunkData(int worldX, int worldY, int worldZ, int stride, int homogenousValue){
this.worldX = worldX; this.worldX = worldX;
this.worldY = worldY; this.worldY = worldY;
this.worldZ = worldZ; this.worldZ = worldZ;
this.stride = stride; this.stride = stride;
this.homogenousValue = homogenousValue;
} }
@ -231,5 +245,13 @@ public class ChunkData {
return stride; return stride;
} }
/**
* The homogenous value of the chunk data
* @return if the data is homogenous, will return the id of the voxel that comprises the whole data block. Otherwise will return ChunkData.NOT_HOMOGENOUS
*/
public int getHomogenousValue(){
return homogenousValue;
}
} }

View File

@ -1,10 +1,10 @@
package electrosphere.client.terrain.cache; package electrosphere.client.terrain.cache;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -25,37 +25,37 @@ public class ClientTerrainCache {
/** /**
* The map of full res chunk key -> chunk data * The map of full res chunk key -> chunk data
*/ */
Map<Long,ChunkData> cacheMapFullRes = new ConcurrentHashMap<Long,ChunkData>(); Map<Long,ChunkData> cacheMapFullRes = new HashMap<Long,ChunkData>();
/** /**
* The map of half res chunk key -> chunk data * The map of half res chunk key -> chunk data
*/ */
Map<Long,ChunkData> cacheMapHalfRes = new ConcurrentHashMap<Long,ChunkData>(); Map<Long,ChunkData> cacheMapHalfRes = new HashMap<Long,ChunkData>();
/** /**
* The map of quarter res chunk key -> chunk data * The map of quarter res chunk key -> chunk data
*/ */
Map<Long,ChunkData> cacheMapQuarterRes = new ConcurrentHashMap<Long,ChunkData>(); Map<Long,ChunkData> cacheMapQuarterRes = new HashMap<Long,ChunkData>();
/** /**
* The map of eighth res chunk key -> chunk data * The map of eighth res chunk key -> chunk data
*/ */
Map<Long,ChunkData> cacheMapEighthRes = new ConcurrentHashMap<Long,ChunkData>(); Map<Long,ChunkData> cacheMapEighthRes = new HashMap<Long,ChunkData>();
/** /**
* The map of sixteenth res chunk key -> chunk data * The map of sixteenth res chunk key -> chunk data
*/ */
Map<Long,ChunkData> cacheMapSixteenthRes = new ConcurrentHashMap<Long,ChunkData>(); Map<Long,ChunkData> cacheMapSixteenthRes = new HashMap<Long,ChunkData>();
/** /**
* The list of keys in the cache * The list of keys in the cache
*/ */
List<Long> cacheList = new CopyOnWriteArrayList<Long>(); List<Long> cacheList = new LinkedList<Long>();
/** /**
* A map of chunk to its world position * A map of chunk to its world position
*/ */
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>(); Map<ChunkData,Vector3i> chunkPositionMap = new HashMap<ChunkData,Vector3i>();
/** /**
* The lock on the terrain cache * The lock on the terrain cache
@ -82,9 +82,47 @@ public class ClientTerrainCache {
Map<Long,ChunkData> cache = this.getCache(chunkData.getStride()); Map<Long,ChunkData> cache = this.getCache(chunkData.getStride());
cache.put(getKey(worldX,worldY,worldZ),chunkData); cache.put(getKey(worldX,worldY,worldZ),chunkData);
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ)); chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
cacheList.add(this.getKey(worldX,worldY,worldZ));
while(cacheList.size() > cacheSize){ while(cacheList.size() > cacheSize){
Long currentChunk = cacheList.remove(0); Long currentKey = cacheList.remove(0);
cache.remove(currentChunk); ChunkData chunk = null;
ChunkData removed = null;
removed = cacheMapFullRes.remove(currentKey);
if(removed != null){
chunk = removed;
}
removed = cacheMapHalfRes.remove(currentKey);
if(removed != null){
chunk = removed;
}
removed = cacheMapQuarterRes.remove(currentKey);
if(removed != null){
chunk = removed;
}
removed = cacheMapEighthRes.remove(currentKey);
if(removed != null){
chunk = removed;
}
removed = cacheMapSixteenthRes.remove(currentKey);
if(removed != null){
chunk = removed;
}
chunkPositionMap.remove(chunk);
}
if(cacheMapFullRes.size() > cacheSize){
throw new Error("Client cache surpassed designated size! " + cacheMapFullRes.size());
}
if(cacheMapHalfRes.size() > cacheSize){
throw new Error("Client cache surpassed designated size! " + cacheMapHalfRes.size());
}
if(cacheMapQuarterRes.size() > cacheSize){
throw new Error("Client cache surpassed designated size! " + cacheMapQuarterRes.size());
}
if(cacheMapEighthRes.size() > cacheSize){
throw new Error("Client cache surpassed designated size! " + cacheMapEighthRes.size());
}
if(cacheMapSixteenthRes.size() > cacheSize){
throw new Error("Client cache surpassed designated size! " + cacheMapSixteenthRes.size());
} }
lock.release(); lock.release();
} }

View File

@ -36,7 +36,7 @@ public class ClientDrawCellManager {
/** /**
* The distance to draw at full resolution * The distance to draw at full resolution
*/ */
public static final double FULL_RES_DIST = 12 * ServerTerrainChunk.CHUNK_DIMENSION; public static final double FULL_RES_DIST = 8 * ServerTerrainChunk.CHUNK_DIMENSION;
/** /**
* The distance for half resolution * The distance for half resolution
@ -301,8 +301,9 @@ public class ClientDrawCellManager {
updated = true; updated = true;
} else if(!node.isLeaf()){ } else if(!node.isLeaf()){
this.validCellCount++; this.validCellCount++;
List<FloatingChunkTreeNode<DrawCell>> children = new LinkedList<FloatingChunkTreeNode<DrawCell>>(node.getChildren()); List<FloatingChunkTreeNode<DrawCell>> children = node.getChildren();
for(FloatingChunkTreeNode<DrawCell> child : children){ for(int i = 0; i < 8; i++){
FloatingChunkTreeNode<DrawCell> child = children.get(i);
boolean childUpdate = recursivelyUpdateCells(child, playerPos, evaluationMap, minLeafLod); boolean childUpdate = recursivelyUpdateCells(child, playerPos, evaluationMap, minLeafLod);
if(childUpdate == true){ if(childUpdate == true){
updated = true; updated = true;

View File

@ -92,7 +92,7 @@ public class DrawCell {
* Generates a drawable entity based on this chunk * Generates a drawable entity based on this chunk
*/ */
public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, List<DrawCellFace> higherLODFaces){ public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, List<DrawCellFace> higherLODFaces){
Globals.profiler.beginCpuSample("DrawCell.fillInData"); Globals.profiler.beginAggregateCpuSample("DrawCell.fillInData");
boolean success = this.fillInData(lod); boolean success = this.fillInData(lod);
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
if(!success){ if(!success){
@ -143,8 +143,8 @@ public class DrawCell {
* Destroys a drawcell including its physics * Destroys a drawcell including its physics
*/ */
public void destroy(){ public void destroy(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
if(modelEntity != null){ if(modelEntity != null){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
collisionEngine.destroyPhysics(modelEntity); collisionEngine.destroyPhysics(modelEntity);
ClientEntityUtils.destroyEntity(modelEntity); ClientEntityUtils.destroyEntity(modelEntity);
} }

View File

@ -4,12 +4,11 @@ import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -35,7 +34,7 @@ import io.github.studiorailgun.HashUtils;
public class ClientTerrainManager { public class ClientTerrainManager {
//queues messages from server //queues messages from server
List<TerrainMessage> messageQueue = new CopyOnWriteArrayList<TerrainMessage>(); List<TerrainMessage> messageQueue = new LinkedList<TerrainMessage>();
/** /**
* Locks the terrain manager (eg if adding message from network) * Locks the terrain manager (eg if adding message from network)
@ -56,7 +55,7 @@ public class ClientTerrainManager {
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO; public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
//caches chunks from server //caches chunks from server
static final int CACHE_SIZE = 1500 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10); static final int CACHE_SIZE = 2500 + (int)(ClientDrawCellManager.FULL_RES_DIST) + (int)(ClientDrawCellManager.HALF_RES_DIST);
/** /**
* Size of the cache in bytes * Size of the cache in bytes
@ -70,12 +69,12 @@ public class ClientTerrainManager {
ClientWorldData clientWorldData; ClientWorldData clientWorldData;
//The queue of terrain chunk data to be buffered to gpu //The queue of terrain chunk data to be buffered to gpu
static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new CopyOnWriteArrayList<TerrainChunkGenQueueItem>(); static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new LinkedList<TerrainChunkGenQueueItem>();
/** /**
* Tracks what outgoing requests are currently active * Tracks what outgoing requests are currently active
*/ */
Map<Long,Integer> requestedMap = new ConcurrentHashMap<Long,Integer>(); Map<Long,Integer> requestedMap = new HashMap<Long,Integer>();
/** /**
* Constructor * Constructor
@ -93,7 +92,6 @@ public class ClientTerrainManager {
lock.acquireUninterruptibly(); lock.acquireUninterruptibly();
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>(); List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
for(TerrainMessage message : messageQueue){ for(TerrainMessage message : messageQueue){
messageQueue.remove(message);
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case SENDCHUNKDATA: { case SENDCHUNKDATA: {
int[][][] values = new int[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE]; int[][][] values = new int[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE];
@ -116,7 +114,7 @@ public class ClientTerrainManager {
} }
} }
} }
ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ(), ChunkData.NO_STRIDE); ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ(), ChunkData.NO_STRIDE, ChunkData.NOT_HOMOGENOUS);
data.setVoxelType(values); data.setVoxelType(values);
data.setVoxelWeight(weights); data.setVoxelWeight(weights);
terrainCache.addChunkDataToCache( terrainCache.addChunkDataToCache(
@ -138,26 +136,27 @@ public class ClientTerrainManager {
} }
IntBuffer intView = buffer.asIntBuffer(); IntBuffer intView = buffer.asIntBuffer();
intView.position(floatBuffer.position()); intView.position(floatBuffer.position());
int firstType = -1;
boolean homogenous = true;
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){ for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){ for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){ for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
values[x][y][z] = intView.get(); values[x][y][z] = intView.get();
if(firstType == -1){
firstType = values[x][y][z];
} else if(homogenous && firstType == values[x][y][z]){
homogenous = false;
}
} }
} }
} }
ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution()); ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution(),homogenous ? firstType : ChunkData.NOT_HOMOGENOUS);
data.setVoxelType(values); data.setVoxelType(values);
data.setVoxelWeight(weights); data.setVoxelWeight(weights);
terrainCache.addChunkDataToCache( terrainCache.addChunkDataToCache(
message.getworldX(), message.getworldY(), message.getworldZ(), message.getworldX(), message.getworldY(), message.getworldZ(),
data data
); );
if(message.getworldX() == 16 && message.getworldY() == 0 && message.getworldZ() == 32){
System.out.println("Received! " + message.getchunkResolution());
for(int i = 0; i < 10; i++){
System.out.println(values[1][i][3]);
}
}
//remove from request map //remove from request map
this.requestedMap.remove(this.getRequestKey(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution())); this.requestedMap.remove(this.getRequestKey(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution()));
} break; } break;
@ -166,6 +165,7 @@ public class ClientTerrainManager {
break; break;
} }
} }
messageQueue.clear();
for(TerrainMessage message : bouncedMessages){ for(TerrainMessage message : bouncedMessages){
messageQueue.add(message); messageQueue.add(message);
} }

View File

@ -56,9 +56,8 @@ public class ImGuiChunkMonitor {
ImGui.text("Chunk Monitor"); ImGui.text("Chunk Monitor");
Globals.clientDrawCellManager.updateStatus(); Globals.clientDrawCellManager.updateStatus();
ImGui.text("Renderable chunks: " + Globals.clientDrawCellManager.getGenerated()); // ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getFullResCacheSize());
ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getMaxResCount()); // ImGui.text("Garbage queue: " + Globals.clientDrawCellManager.getGarbageSize());
ImGui.text("Half res chunks: " + Globals.clientDrawCellManager.getHalfResCount());
//client network pressure //client network pressure

View File

@ -0,0 +1,105 @@
package electrosphere.client.ui.menu.debug;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
import electrosphere.engine.Globals;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot.ImGuiLinePlotDataset;
import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import imgui.ImGui;
/**
* Debug menu for memory profiling
*/
public class ImGuiMemory {
/**
* Size of a kilobyte
*/
static final long KB = 1024;
/**
* Size of a megabyte
*/
static final long MB = 1024 * 1024;
/**
* Size of a gigabyte
*/
static final long GB = 1024 * 1024 * 1024;
/**
* Number of points on the graph
*/
static final int GRAPH_POINT_COUNT = 50;
//window for viewing information about the memory usage
protected static ImGuiWindow memoryWindow;
/**
* Creates the windows in this file
*/
protected static void createMemoryWindows(){
createMemoryDebugWindow();
}
/**
* Memory window
*/
protected static void createMemoryDebugWindow(){
//memory usage graph
ImGuiLinePlot memoryGraph = new ImGuiLinePlot("Memory Usage",400,400);
ImGuiLinePlotDataset memoryGraphDataset = new ImGuiLinePlotDataset("Memory Usage (mb)", GRAPH_POINT_COUNT);
memoryGraphDataset.zeroOut();
memoryGraph.addDataset(memoryGraphDataset);
memoryWindow = new ImGuiWindow("Memory Usage");
memoryWindow.setCallback(new ImGuiWindowCallback() {
@Override
public void exec() {
//get garbage collector name
List<GarbageCollectorMXBean> gcMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
if(gcMxBeans != null && gcMxBeans.size() > 0){
GarbageCollectorMXBean gcMxBean = gcMxBeans.get(0);
ImGui.text(gcMxBean.getName() + " - " + gcMxBean.getObjectName());
}
//get memory usage
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long memoryUsage = totalMemory - freeMemory;
ImGui.text("Total Memory: " + formatMemory(totalMemory));
ImGui.text("Free Memory: " + formatMemory(freeMemory));
ImGui.text("Memory Usage: " + formatMemory(memoryUsage));
//memory usage graph
memoryGraphDataset.addPoint(memoryUsage);
memoryGraph.draw();
}
});
memoryWindow.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(memoryWindow);
}
/**
* Formats a memory value
* @param memoryRaw The memory value
* @return The formatted string
*/
private static String formatMemory(long memoryRaw){
if(memoryRaw < KB){
return "" + memoryRaw;
} else if(memoryRaw < MB){
return (memoryRaw / KB) + "kb";
} else {
return (memoryRaw / MB) + "mb";
}
}
}

View File

@ -53,6 +53,7 @@ public class ImGuiWindowMacros {
ImGuiTestGen.createTestGenWindows(); ImGuiTestGen.createTestGenWindows();
ImGuiChunkMonitor.createChunkMonitorWindows(); ImGuiChunkMonitor.createChunkMonitorWindows();
ImGuiGriddedManager.createGriddedManagerWindows(); ImGuiGriddedManager.createGriddedManagerWindows();
ImGuiMemory.createMemoryWindows();
} }
/** /**
@ -114,10 +115,11 @@ public class ImGuiWindowMacros {
fluidWindow.setCallback(new ImGuiWindowCallback() { fluidWindow.setCallback(new ImGuiWindowCallback() {
@Override @Override
public void exec() { public void exec() {
ServerFluidManager fluidManager = Globals.playerManager.getPlayerRealm(Globals.clientPlayer).getServerWorldData().getServerFluidManager();
//audio engine details //audio engine details
ImGui.text("Fluids Debug"); ImGui.text("Fluids Debug");
ImGui.text("State: " + (fluidManager.getSimulate() ? "on" : "off"));
if(ImGui.button("Toggle Simulation")){ if(ImGui.button("Toggle Simulation")){
ServerFluidManager fluidManager = Globals.playerManager.getPlayerRealm(Globals.clientPlayer).getServerWorldData().getServerFluidManager();
fluidManager.setSimulate(!fluidManager.getSimulate()); fluidManager.setSimulate(!fluidManager.getSimulate());
} }
} }
@ -193,6 +195,10 @@ public class ImGuiWindowMacros {
if(ImGui.button("Gridded Data Cell Monitor")){ if(ImGui.button("Gridded Data Cell Monitor")){
ImGuiGriddedManager.griddedManagerWindow.setOpen(true); ImGuiGriddedManager.griddedManagerWindow.setOpen(true);
} }
//memory usage
if(ImGui.button("Memory Usage")){
ImGuiMemory.memoryWindow.setOpen(!ImGuiMemory.memoryWindow.isOpen());
}
//close button //close button
if(ImGui.button("Close")){ if(ImGui.button("Close")){
mainDebugWindow.setOpen(false); mainDebugWindow.setOpen(false);

View File

@ -722,10 +722,10 @@ public class CollisionEngine {
//make uncollidable //make uncollidable
if(PhysicsEntityUtils.containsDBody(e)){ if(PhysicsEntityUtils.containsDBody(e)){
DBody rigidBody = PhysicsEntityUtils.getDBody(e); DBody rigidBody = PhysicsEntityUtils.getDBody(e);
deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e)); this.deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e));
e.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY); e.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY);
if(rigidBody != null){ if(rigidBody != null){
deregisterPhysicsObject(rigidBody); this.deregisterPhysicsObject(rigidBody);
} }
} }
if(ServerPhysicsSyncTree.hasTree(e)){ if(ServerPhysicsSyncTree.hasTree(e)){

View File

@ -154,6 +154,10 @@ public class Globals {
//set to true to trigger full GC every frame //set to true to trigger full GC every frame
//a full GC includes collecting old generations as well -- likely very laggy!! //a full GC includes collecting old generations as well -- likely very laggy!!
public static boolean EXPLICIT_GC = false; public static boolean EXPLICIT_GC = false;
/**
* Number of frames to wait before triggering gc again
*/
public static final int GC_FRAME_FREQUENCY = 15;
// //

View File

@ -376,7 +376,7 @@ public class Main {
/// G A R B A G E C H E C K /// G A R B A G E C H E C K
/// ///
Globals.profiler.beginCpuSample("gc"); Globals.profiler.beginCpuSample("gc");
if(Globals.EXPLICIT_GC){ if(Globals.EXPLICIT_GC && Globals.timekeeper.getNumberOfRenderFramesElapsed() % Globals.GC_FRAME_FREQUENCY == 0){
System.gc(); System.gc();
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();

View File

@ -41,7 +41,7 @@ public class TerrainChunk {
* @return The terrain chunk entity * @return The terrain chunk entity
*/ */
public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas, boolean hasPolygons){ public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas, boolean hasPolygons){
Globals.profiler.beginCpuSample("TerrainChunk.clientCreateTerrainChunkEntity"); Globals.profiler.beginAggregateCpuSample("TerrainChunk.clientCreateTerrainChunkEntity");
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();

View File

@ -45,7 +45,7 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
@Override @Override
public void handleSyncMessage(EntityMessage message) { public void handleSyncMessage(EntityMessage message) {
Globals.profiler.beginCpuSample("EntityProtocol.handleEntityMessage"); Globals.profiler.beginAggregateCpuSample("EntityProtocol.handleEntityMessage");
LoggerInterface.loggerNetworking.DEBUG_LOOP("Parse entity message of type " + message.getMessageSubtype()); LoggerInterface.loggerNetworking.DEBUG_LOOP("Parse entity message of type " + message.getMessageSubtype());
//error check //error check

View File

@ -28,7 +28,7 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
@Override @Override
public void handleSyncMessage(TerrainMessage message) { public void handleSyncMessage(TerrainMessage message) {
Globals.profiler.beginCpuSample("TerrainProtocol.handleTerrainMessage"); Globals.profiler.beginAggregateCpuSample("TerrainProtocol.handleTerrainMessage");
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case RESPONSEMETADATA: case RESPONSEMETADATA:
Globals.clientWorldData = new ClientWorldData( Globals.clientWorldData = new ClientWorldData(

View File

@ -3,7 +3,7 @@ package electrosphere.server.terrain.generation;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.graalvm.polyglot.Value; // import org.graalvm.polyglot.Value;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.game.data.biome.BiomeData; import electrosphere.game.data.biome.BiomeData;
@ -94,9 +94,6 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];; float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];;
int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION]; int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
if(worldX == 16 && worldY == 0 && worldZ == 32){
System.out.println(worldX + " " + worldY + " " + worldZ);
}
try { try {
//actual generation algo //actual generation algo
@ -129,34 +126,34 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
} }
if(this.useJavascript){ if(this.useJavascript){
Globals.scriptEngine.executeSynchronously(() -> { // Globals.scriptEngine.executeSynchronously(() -> {
Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG); // Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ // for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice"); // Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){ // for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ // for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); // int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); // int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); // int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; // int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; // int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; // int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
Value result = getVoxelFunc.execute( // Value result = getVoxelFunc.execute(
finalWorldX, finalWorldY, finalWorldZ, // finalWorldX, finalWorldY, finalWorldZ,
finalChunkX, finalChunkY, finalChunkZ, // finalChunkX, finalChunkY, finalChunkZ,
stride, // stride,
heightfield[x][z], // heightfield[x][z],
surfaceBiome // surfaceBiome
); // );
if(result != null){ // if(result != null){
weights[x][y][z] = result.getMember("weight").asFloat(); // weights[x][y][z] = result.getMember("weight").asFloat();
values[x][y][z] = result.getMember("type").asInt(); // values[x][y][z] = result.getMember("type").asInt();
} // }
} // }
} // }
Globals.profiler.endCpuSample(); // Globals.profiler.endCpuSample();
} // }
}); // });
} else { } else {
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice"); Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");

View File

@ -19,7 +19,7 @@ public class ServerChunkCache {
/** /**
* Number of chunks to cache * Number of chunks to cache
*/ */
static final int CACHE_SIZE = 2500; static final int CACHE_SIZE = 1500;
/** /**
* The size of the cache * The size of the cache
@ -124,6 +124,14 @@ public class ServerChunkCache {
queryRecencyQueue.add(0, key); queryRecencyQueue.add(0, key);
Map<Long,ServerTerrainChunk> cache = this.getCache(stride); Map<Long,ServerTerrainChunk> cache = this.getCache(stride);
cache.put(key, chunk); cache.put(key, chunk);
while(queryRecencyQueue.size() > cacheSize){
Long oldKey = queryRecencyQueue.remove(queryRecencyQueue.size() - 1);
cacheMapFullRes.remove(oldKey);
cacheMapHalfRes.remove(oldKey);
cacheMapQuarterRes.remove(oldKey);
cacheMapEighthRes.remove(oldKey);
cacheMapSixteenthRes.remove(oldKey);
}
lock.release(); lock.release();
} }

View File

@ -38,6 +38,7 @@ public class ClientDrawCellManagerTests {
int worldDiscreteSize = 64; int worldDiscreteSize = 64;
Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), 0, worldDiscreteSize); Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), 0, worldDiscreteSize);
ClientDrawCellManager manager = new ClientDrawCellManager(null, 64); ClientDrawCellManager manager = new ClientDrawCellManager(null, 64);
double precomputedMidDist = 0;
Vector3d playerPos = new Vector3d(0,0,0); Vector3d playerPos = new Vector3d(0,0,0);
FloatingChunkTreeNode<DrawCell> node = FloatingChunkTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16)); FloatingChunkTreeNode<DrawCell> node = FloatingChunkTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
node.convertToLeaf(DrawCell.generateTerrainCell(new Vector3i(0,0,0))); node.convertToLeaf(DrawCell.generateTerrainCell(new Vector3i(0,0,0)));