ClientDrawCellManager optimizations
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
221bcd70a7
commit
4d6db78059
5
.gitignore
vendored
5
.gitignore
vendored
@ -63,3 +63,8 @@
|
||||
|
||||
#General cache for the engine
|
||||
/.cache
|
||||
|
||||
#Memory debug files
|
||||
/heap.dump
|
||||
/heap.dump.hwcache
|
||||
/tmp
|
||||
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@ -8,14 +8,15 @@
|
||||
"type": "java",
|
||||
"name": "Launch Current File",
|
||||
"request": "launch",
|
||||
"mainClass": "${file}"
|
||||
"mainClass": "${file}",
|
||||
"vmArgs": "-Xmx4G -Xms1024m -XX:+UseZGC -XX:SoftMaxHeapSize=3G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\"./tmp/heap.dump\""
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Launch Main",
|
||||
"request": "launch",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
@ -23,7 +24,7 @@
|
||||
"name": "Launch Main (Debug Memory)",
|
||||
"request": "launch",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
@ -34,7 +35,7 @@
|
||||
"env": {
|
||||
"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"
|
||||
},
|
||||
{
|
||||
|
||||
@ -973,6 +973,10 @@ ScriptEngine full re-initialization signal
|
||||
Add surface width to test generator
|
||||
User setting to toggle foliage manager
|
||||
Fix client terrain cache lookup bug
|
||||
Memory debugging work + update memory flags in launch file
|
||||
|
||||
(11/10/2024)
|
||||
Attempts at optimizing ClientDrawCellManager
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -122,7 +122,7 @@ public class ClientSceneWrapper {
|
||||
* @param clientEntity The client entity
|
||||
*/
|
||||
public void deregisterTranslationMapping(Entity clientEntity){
|
||||
if(clientToServerMapContainsId(clientEntity.getId())){
|
||||
if(this.clientToServerMapContainsId(clientEntity.getId())){
|
||||
//remove from client->server map
|
||||
int serverId = clientToServerIdMap.remove(clientEntity.getId());
|
||||
//remove from server->client map
|
||||
|
||||
@ -17,6 +17,11 @@ public class ChunkData {
|
||||
*/
|
||||
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
|
||||
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
|
||||
@ -35,10 +40,12 @@ public class ChunkData {
|
||||
* The word x coordinate
|
||||
*/
|
||||
int worldX;
|
||||
|
||||
/**
|
||||
* The word y coordinate
|
||||
*/
|
||||
int worldY;
|
||||
|
||||
/**
|
||||
* The word z coordinate
|
||||
*/
|
||||
@ -49,18 +56,25 @@ public class ChunkData {
|
||||
*/
|
||||
int stride;
|
||||
|
||||
/**
|
||||
* Tracks whether this chunk is homogenous or not
|
||||
*/
|
||||
int homogenousValue = NOT_HOMOGENOUS;
|
||||
|
||||
/**
|
||||
* Creates a chunk data
|
||||
* @param worldX The word x coordinate
|
||||
* @param worldY The word y coordinate
|
||||
* @param worldZ The word z coordinate
|
||||
* @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.worldY = worldY;
|
||||
this.worldZ = worldZ;
|
||||
this.stride = stride;
|
||||
this.homogenousValue = homogenousValue;
|
||||
}
|
||||
|
||||
|
||||
@ -231,5 +245,13 @@ public class ChunkData {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package electrosphere.client.terrain.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
@ -25,37 +25,37 @@ public class ClientTerrainCache {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
Map<Long,ChunkData> cacheMapSixteenthRes = new ConcurrentHashMap<Long,ChunkData>();
|
||||
Map<Long,ChunkData> cacheMapSixteenthRes = new HashMap<Long,ChunkData>();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
||||
Map<ChunkData,Vector3i> chunkPositionMap = new HashMap<ChunkData,Vector3i>();
|
||||
|
||||
/**
|
||||
* The lock on the terrain cache
|
||||
@ -82,9 +82,47 @@ public class ClientTerrainCache {
|
||||
Map<Long,ChunkData> cache = this.getCache(chunkData.getStride());
|
||||
cache.put(getKey(worldX,worldY,worldZ),chunkData);
|
||||
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
||||
cacheList.add(this.getKey(worldX,worldY,worldZ));
|
||||
while(cacheList.size() > cacheSize){
|
||||
Long currentChunk = cacheList.remove(0);
|
||||
cache.remove(currentChunk);
|
||||
Long currentKey = cacheList.remove(0);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ public class ClientDrawCellManager {
|
||||
/**
|
||||
* 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
|
||||
@ -301,8 +301,9 @@ public class ClientDrawCellManager {
|
||||
updated = true;
|
||||
} else if(!node.isLeaf()){
|
||||
this.validCellCount++;
|
||||
List<FloatingChunkTreeNode<DrawCell>> children = new LinkedList<FloatingChunkTreeNode<DrawCell>>(node.getChildren());
|
||||
for(FloatingChunkTreeNode<DrawCell> child : children){
|
||||
List<FloatingChunkTreeNode<DrawCell>> children = node.getChildren();
|
||||
for(int i = 0; i < 8; i++){
|
||||
FloatingChunkTreeNode<DrawCell> child = children.get(i);
|
||||
boolean childUpdate = recursivelyUpdateCells(child, playerPos, evaluationMap, minLeafLod);
|
||||
if(childUpdate == true){
|
||||
updated = true;
|
||||
|
||||
@ -92,7 +92,7 @@ public class DrawCell {
|
||||
* Generates a drawable entity based on this chunk
|
||||
*/
|
||||
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);
|
||||
Globals.profiler.endCpuSample();
|
||||
if(!success){
|
||||
@ -143,8 +143,8 @@ public class DrawCell {
|
||||
* Destroys a drawcell including its physics
|
||||
*/
|
||||
public void destroy(){
|
||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||
if(modelEntity != null){
|
||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||
collisionEngine.destroyPhysics(modelEntity);
|
||||
ClientEntityUtils.destroyEntity(modelEntity);
|
||||
}
|
||||
|
||||
@ -4,12 +4,11 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
@ -35,7 +34,7 @@ import io.github.studiorailgun.HashUtils;
|
||||
public class ClientTerrainManager {
|
||||
|
||||
//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)
|
||||
@ -56,7 +55,7 @@ public class ClientTerrainManager {
|
||||
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
|
||||
|
||||
//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
|
||||
@ -70,12 +69,12 @@ public class ClientTerrainManager {
|
||||
ClientWorldData clientWorldData;
|
||||
|
||||
//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
|
||||
*/
|
||||
Map<Long,Integer> requestedMap = new ConcurrentHashMap<Long,Integer>();
|
||||
Map<Long,Integer> requestedMap = new HashMap<Long,Integer>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -93,7 +92,6 @@ public class ClientTerrainManager {
|
||||
lock.acquireUninterruptibly();
|
||||
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
|
||||
for(TerrainMessage message : messageQueue){
|
||||
messageQueue.remove(message);
|
||||
switch(message.getMessageSubtype()){
|
||||
case SENDCHUNKDATA: {
|
||||
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.setVoxelWeight(weights);
|
||||
terrainCache.addChunkDataToCache(
|
||||
@ -138,26 +136,27 @@ public class ClientTerrainManager {
|
||||
}
|
||||
IntBuffer intView = buffer.asIntBuffer();
|
||||
intView.position(floatBuffer.position());
|
||||
int firstType = -1;
|
||||
boolean homogenous = true;
|
||||
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
||||
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
|
||||
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||
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.setVoxelWeight(weights);
|
||||
terrainCache.addChunkDataToCache(
|
||||
message.getworldX(), message.getworldY(), message.getworldZ(),
|
||||
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
|
||||
this.requestedMap.remove(this.getRequestKey(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution()));
|
||||
} break;
|
||||
@ -166,6 +165,7 @@ public class ClientTerrainManager {
|
||||
break;
|
||||
}
|
||||
}
|
||||
messageQueue.clear();
|
||||
for(TerrainMessage message : bouncedMessages){
|
||||
messageQueue.add(message);
|
||||
}
|
||||
|
||||
@ -56,9 +56,8 @@ public class ImGuiChunkMonitor {
|
||||
ImGui.text("Chunk Monitor");
|
||||
|
||||
Globals.clientDrawCellManager.updateStatus();
|
||||
ImGui.text("Renderable chunks: " + Globals.clientDrawCellManager.getGenerated());
|
||||
ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getMaxResCount());
|
||||
ImGui.text("Half res chunks: " + Globals.clientDrawCellManager.getHalfResCount());
|
||||
// ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getFullResCacheSize());
|
||||
// ImGui.text("Garbage queue: " + Globals.clientDrawCellManager.getGarbageSize());
|
||||
|
||||
|
||||
//client network pressure
|
||||
|
||||
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -53,6 +53,7 @@ public class ImGuiWindowMacros {
|
||||
ImGuiTestGen.createTestGenWindows();
|
||||
ImGuiChunkMonitor.createChunkMonitorWindows();
|
||||
ImGuiGriddedManager.createGriddedManagerWindows();
|
||||
ImGuiMemory.createMemoryWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,10 +115,11 @@ public class ImGuiWindowMacros {
|
||||
fluidWindow.setCallback(new ImGuiWindowCallback() {
|
||||
@Override
|
||||
public void exec() {
|
||||
ServerFluidManager fluidManager = Globals.playerManager.getPlayerRealm(Globals.clientPlayer).getServerWorldData().getServerFluidManager();
|
||||
//audio engine details
|
||||
ImGui.text("Fluids Debug");
|
||||
ImGui.text("State: " + (fluidManager.getSimulate() ? "on" : "off"));
|
||||
if(ImGui.button("Toggle Simulation")){
|
||||
ServerFluidManager fluidManager = Globals.playerManager.getPlayerRealm(Globals.clientPlayer).getServerWorldData().getServerFluidManager();
|
||||
fluidManager.setSimulate(!fluidManager.getSimulate());
|
||||
}
|
||||
}
|
||||
@ -193,6 +195,10 @@ public class ImGuiWindowMacros {
|
||||
if(ImGui.button("Gridded Data Cell Monitor")){
|
||||
ImGuiGriddedManager.griddedManagerWindow.setOpen(true);
|
||||
}
|
||||
//memory usage
|
||||
if(ImGui.button("Memory Usage")){
|
||||
ImGuiMemory.memoryWindow.setOpen(!ImGuiMemory.memoryWindow.isOpen());
|
||||
}
|
||||
//close button
|
||||
if(ImGui.button("Close")){
|
||||
mainDebugWindow.setOpen(false);
|
||||
|
||||
@ -722,10 +722,10 @@ public class CollisionEngine {
|
||||
//make uncollidable
|
||||
if(PhysicsEntityUtils.containsDBody(e)){
|
||||
DBody rigidBody = PhysicsEntityUtils.getDBody(e);
|
||||
deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e));
|
||||
this.deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e));
|
||||
e.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY);
|
||||
if(rigidBody != null){
|
||||
deregisterPhysicsObject(rigidBody);
|
||||
this.deregisterPhysicsObject(rigidBody);
|
||||
}
|
||||
}
|
||||
if(ServerPhysicsSyncTree.hasTree(e)){
|
||||
|
||||
@ -154,6 +154,10 @@ public class Globals {
|
||||
//set to true to trigger full GC every frame
|
||||
//a full GC includes collecting old generations as well -- likely very laggy!!
|
||||
public static boolean EXPLICIT_GC = false;
|
||||
/**
|
||||
* Number of frames to wait before triggering gc again
|
||||
*/
|
||||
public static final int GC_FRAME_FREQUENCY = 15;
|
||||
|
||||
|
||||
//
|
||||
|
||||
@ -376,7 +376,7 @@ public class Main {
|
||||
/// G A R B A G E C H E C K
|
||||
///
|
||||
Globals.profiler.beginCpuSample("gc");
|
||||
if(Globals.EXPLICIT_GC){
|
||||
if(Globals.EXPLICIT_GC && Globals.timekeeper.getNumberOfRenderFramesElapsed() % Globals.GC_FRAME_FREQUENCY == 0){
|
||||
System.gc();
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
@ -41,7 +41,7 @@ public class TerrainChunk {
|
||||
* @return The terrain chunk entity
|
||||
*/
|
||||
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();
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
|
||||
@Override
|
||||
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());
|
||||
|
||||
//error check
|
||||
|
||||
@ -28,7 +28,7 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
|
||||
|
||||
@Override
|
||||
public void handleSyncMessage(TerrainMessage message) {
|
||||
Globals.profiler.beginCpuSample("TerrainProtocol.handleTerrainMessage");
|
||||
Globals.profiler.beginAggregateCpuSample("TerrainProtocol.handleTerrainMessage");
|
||||
switch(message.getMessageSubtype()){
|
||||
case RESPONSEMETADATA:
|
||||
Globals.clientWorldData = new ClientWorldData(
|
||||
|
||||
@ -3,7 +3,7 @@ package electrosphere.server.terrain.generation;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.graalvm.polyglot.Value;
|
||||
// import org.graalvm.polyglot.Value;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
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];;
|
||||
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 {
|
||||
//actual generation algo
|
||||
|
||||
@ -129,34 +126,34 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
}
|
||||
|
||||
if(this.useJavascript){
|
||||
Globals.scriptEngine.executeSynchronously(() -> {
|
||||
Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
|
||||
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
|
||||
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
||||
int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
Value result = getVoxelFunc.execute(
|
||||
finalWorldX, finalWorldY, finalWorldZ,
|
||||
finalChunkX, finalChunkY, finalChunkZ,
|
||||
stride,
|
||||
heightfield[x][z],
|
||||
surfaceBiome
|
||||
);
|
||||
if(result != null){
|
||||
weights[x][y][z] = result.getMember("weight").asFloat();
|
||||
values[x][y][z] = result.getMember("type").asInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
});
|
||||
// Globals.scriptEngine.executeSynchronously(() -> {
|
||||
// Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
|
||||
// for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||
// Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
// for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
|
||||
// for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
||||
// int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// Value result = getVoxelFunc.execute(
|
||||
// finalWorldX, finalWorldY, finalWorldZ,
|
||||
// finalChunkX, finalChunkY, finalChunkZ,
|
||||
// stride,
|
||||
// heightfield[x][z],
|
||||
// surfaceBiome
|
||||
// );
|
||||
// if(result != null){
|
||||
// weights[x][y][z] = result.getMember("weight").asFloat();
|
||||
// values[x][y][z] = result.getMember("type").asInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// });
|
||||
} else {
|
||||
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
|
||||
@ -19,7 +19,7 @@ public class ServerChunkCache {
|
||||
/**
|
||||
* Number of chunks to cache
|
||||
*/
|
||||
static final int CACHE_SIZE = 2500;
|
||||
static final int CACHE_SIZE = 1500;
|
||||
|
||||
/**
|
||||
* The size of the cache
|
||||
@ -124,6 +124,14 @@ public class ServerChunkCache {
|
||||
queryRecencyQueue.add(0, key);
|
||||
Map<Long,ServerTerrainChunk> cache = this.getCache(stride);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ public class ClientDrawCellManagerTests {
|
||||
int worldDiscreteSize = 64;
|
||||
Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), 0, worldDiscreteSize);
|
||||
ClientDrawCellManager manager = new ClientDrawCellManager(null, 64);
|
||||
double precomputedMidDist = 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));
|
||||
node.convertToLeaf(DrawCell.generateTerrainCell(new Vector3i(0,0,0)));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user