Prep v2
This commit is contained in:
@@ -7,6 +7,7 @@ import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
||||
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter;
|
||||
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalNodeManager;
|
||||
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
||||
import me.cortex.voxy.client.core.rendering.hierachical2.NodeManager2;
|
||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionRenderer;
|
||||
import me.cortex.voxy.client.core.rendering.section.IUsesMeshlets;
|
||||
import me.cortex.voxy.client.core.rendering.section.MDICSectionRenderer;
|
||||
@@ -33,7 +34,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
private final ViewportSelector<?> viewportSelector;
|
||||
private final AbstractSectionRenderer<J, ?> sectionRenderer;
|
||||
|
||||
private final HierarchicalNodeManager nodeManager;
|
||||
private final NodeManager2 nodeManager;
|
||||
private final HierarchicalOcclusionTraverser traversal;
|
||||
private final ModelBakerySubsystem modelService;
|
||||
private final RenderGenerationService renderGen;
|
||||
@@ -51,7 +52,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
||||
//Do something incredibly hacky, we dont need to keep the reference to this around, so just connect and discard
|
||||
var router = new SectionUpdateRouter();
|
||||
|
||||
this.nodeManager = new HierarchicalNodeManager(1<<21, this.sectionRenderer.getGeometryManager(), router);
|
||||
this.nodeManager = new NodeManager2(1<<21, this.sectionRenderer.getGeometryManager(), router);
|
||||
|
||||
this.sectionUpdateQueue = new MessageQueue<>(section -> {
|
||||
byte childExistence = section.getNonEmptyChildren();
|
||||
|
||||
@@ -230,7 +230,7 @@ public class HierarchicalNodeManager {
|
||||
//============================================================================================================================================
|
||||
public void processChildChange(long position, byte childExistence) {
|
||||
if (childExistence == 0) {
|
||||
Logger.logError("Section at " + WorldEngine.pprintPos(position) + " had empty child existence!!");
|
||||
Logger.error("Section at " + WorldEngine.pprintPos(position) + " had empty child existence!!");
|
||||
}
|
||||
int nodeId = this.activeSectionMap.get(position);
|
||||
if (nodeId == NO_NODE) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import static org.lwjgl.opengl.GL45.*;
|
||||
|
||||
// TODO: swap to persistent gpu threads instead of dispatching MAX_ITERATIONS of compute layers
|
||||
public class HierarchicalOcclusionTraverser {
|
||||
private final HierarchicalNodeManager nodeManager;
|
||||
private final NodeManager2 nodeManager;
|
||||
|
||||
private final int maxRequestCount;
|
||||
private final GlBuffer requestBuffer;
|
||||
@@ -77,7 +77,7 @@ public class HierarchicalOcclusionTraverser {
|
||||
.compile();
|
||||
|
||||
|
||||
public HierarchicalOcclusionTraverser(HierarchicalNodeManager nodeManager, int requestBufferCount) {
|
||||
public HierarchicalOcclusionTraverser(NodeManager2 nodeManager, int requestBufferCount) {
|
||||
this.nodeManager = nodeManager;
|
||||
this.requestBuffer = new GlBuffer(requestBufferCount*4L+1024).zero();//The 1024 is to assist with race condition issues
|
||||
this.nodeBuffer = new GlBuffer(nodeManager.maxNodeCount*16L).zero();
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package me.cortex.voxy.client.core.rendering.hierachical2;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import me.cortex.voxy.client.core.VoxelCore;
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter;
|
||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||
import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList;
|
||||
import me.cortex.voxy.common.Logger;
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||
import me.jellysquid.mods.sodium.client.util.MathUtil;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import static me.cortex.voxy.client.core.rendering.hierachical2.NodeStore.NODE_ID_MSK;
|
||||
|
||||
public class NodeManager2 {
|
||||
//Assumptions:
|
||||
// all nodes have children (i.e. all nodes have at least one child existence bit set at all times)
|
||||
// leaf nodes always contain geometry (empty geometry counts as geometry (it just doesnt take any memory to store))
|
||||
// All nodes except top nodes have parents
|
||||
|
||||
//NOTE:
|
||||
// For the queue processing, will need a redirect node-value type
|
||||
// since for inner node child resize gpu could take N frames to update
|
||||
|
||||
|
||||
private final ExpandingObjectAllocationList<NodeChildRequest> childRequests = new ExpandingObjectAllocationList<>(NodeChildRequest[]::new);
|
||||
private final IntOpenHashSet nodeUpdates = new IntOpenHashSet();
|
||||
private final AbstractSectionGeometryManager geometryManager;
|
||||
private final SectionUpdateRouter updateRouter;
|
||||
private final Long2IntOpenHashMap activeSectionMap = new Long2IntOpenHashMap();
|
||||
private final NodeStore nodeData;
|
||||
public final int maxNodeCount;
|
||||
public NodeManager2(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionUpdateRouter updateRouter) {
|
||||
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
|
||||
throw new IllegalArgumentException("Max node count must be a power of 2");
|
||||
}
|
||||
if (maxNodeCount>(1<<24)) {
|
||||
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
|
||||
}
|
||||
this.activeSectionMap.defaultReturnValue(-1);
|
||||
this.updateRouter = updateRouter;
|
||||
this.maxNodeCount = maxNodeCount;
|
||||
this.nodeData = new NodeStore(maxNodeCount);
|
||||
this.geometryManager = geometryManager;
|
||||
}
|
||||
|
||||
public void insertTopLevelNode(long pos) {
|
||||
|
||||
}
|
||||
|
||||
public void removeTopLevelNode(long pos) {
|
||||
|
||||
}
|
||||
|
||||
public void processGeometryResult(BuiltSection sectionResult) {
|
||||
|
||||
}
|
||||
|
||||
//============================================================================================================================================
|
||||
public void processRequestQueue(int count, long ptr) {
|
||||
for (int requestIndex = 0; requestIndex < count; requestIndex++) {
|
||||
int op = MemoryUtil.memGetInt(ptr + (requestIndex * 4L));
|
||||
this.processRequest(op);
|
||||
}
|
||||
}
|
||||
|
||||
private void processRequest(int op) {
|
||||
int node = op & NODE_ID_MSK;
|
||||
if (!this.nodeData.nodeExists(node)) {
|
||||
throw new IllegalStateException("Tried processing a node that doesnt exist: " + node);
|
||||
}
|
||||
if (this.nodeData.isNodeRequestInFlight(node)) {
|
||||
Logger.warn("Tried processing a node that already has a request in flight: " + node + " pos: " + WorldEngine.pprintPos(this.nodeData.nodePosition(node)));
|
||||
return;
|
||||
}
|
||||
this.nodeData.markRequestInFlight(node);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void processChildChange(long pos, byte childExistence) {
|
||||
|
||||
}
|
||||
|
||||
public boolean writeChanges(GlBuffer nodeBuffer) {
|
||||
//TODO: use like compute based copy system or something
|
||||
// since microcopies are bad
|
||||
if (this.nodeUpdates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (int i : this.nodeUpdates) {
|
||||
this.nodeData.writeNode(UploadStream.INSTANCE.upload(nodeBuffer, i*16L, 16L), i);
|
||||
}
|
||||
this.nodeUpdates.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package me.cortex.voxy.client.core.rendering.hierachical2;
|
||||
|
||||
class SingleNodeRequest {
|
||||
private final long nodePos;
|
||||
private int mesh;
|
||||
private byte childExistence;
|
||||
private int setMsk;
|
||||
|
||||
SingleNodeRequest(long nodePos) {
|
||||
this.nodePos = nodePos;
|
||||
}
|
||||
|
||||
public void setChildExistence(byte childExistence) {
|
||||
this.setMsk |= 2;
|
||||
this.childExistence = childExistence;
|
||||
}
|
||||
|
||||
public int setMesh(int mesh) {
|
||||
this.setMsk |= 1;
|
||||
int prev = this.mesh;
|
||||
this.mesh = mesh;
|
||||
return prev;
|
||||
}
|
||||
|
||||
public boolean isSatisfied() {
|
||||
return this.setMsk == 3;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return this.nodePos;
|
||||
}
|
||||
|
||||
public int getMesh() {
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
public byte getChildExistence() {
|
||||
return this.childExistence;
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,13 @@ package me.cortex.voxy.common;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Logger {
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger("Voxy");
|
||||
|
||||
public static void logError(Object... args) {
|
||||
public static void error(Object... args) {
|
||||
Throwable throwable = null;
|
||||
for (var i : args) {
|
||||
if (i instanceof Throwable) {
|
||||
@@ -19,4 +18,15 @@ public class Logger {
|
||||
var stackEntry = new Throwable().getStackTrace()[1];
|
||||
LOGGER.error("["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" ")), throwable);
|
||||
}
|
||||
|
||||
public static void warn(Object... args) {
|
||||
Throwable throwable = null;
|
||||
for (var i : args) {
|
||||
if (i instanceof Throwable) {
|
||||
throwable = (Throwable) i;
|
||||
}
|
||||
}
|
||||
var stackEntry = new Throwable().getStackTrace()[1];
|
||||
LOGGER.warn("["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" ")), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,16 @@
|
||||
package me.cortex.voxy.commonImpl.mixin.minecraft;
|
||||
|
||||
import me.cortex.voxy.client.Voxy;
|
||||
import me.cortex.voxy.common.Logger;
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
import me.cortex.voxy.commonImpl.IVoxyWorldGetter;
|
||||
import me.cortex.voxy.commonImpl.IVoxyWorldSetter;
|
||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.world.MutableWorldProperties;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(World.class)
|
||||
public class MixinWorld implements IVoxyWorldGetter, IVoxyWorldSetter {
|
||||
@Unique private WorldEngine voxyWorld;
|
||||
@@ -31,7 +19,7 @@ public class MixinWorld implements IVoxyWorldGetter, IVoxyWorldSetter {
|
||||
private void closeVoxyWorld(CallbackInfo ci) {
|
||||
if (this.voxyWorld != null) {
|
||||
try {this.voxyWorld.shutdown();this.voxyWorld = null;} catch (Exception e) {
|
||||
Logger.logError("Failed to shutdown voxy world engine.", e);
|
||||
Logger.error("Failed to shutdown voxy world engine.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user