Update forwarding and checking

This commit is contained in:
mcrcortex
2024-08-05 22:10:21 +10:00
parent 593f222760
commit 2d6d948e80
5 changed files with 114 additions and 22 deletions

View File

@@ -5,6 +5,7 @@ import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
import me.cortex.voxy.client.core.model.ModelStore;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.building.SectionPositionUpdateFilterer;
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.section.AbstractSectionRenderer;
@@ -13,6 +14,7 @@ import me.cortex.voxy.client.core.rendering.section.MDICSectionRenderer;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.common.world.WorldSection;
import net.minecraft.client.render.Camera;
import java.util.Arrays;
@@ -38,7 +40,6 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
private final ConcurrentLinkedDeque<BuiltSection> sectionBuildResultQueue = new ConcurrentLinkedDeque<>();
public RenderService(WorldEngine world) {
this.modelService = new ModelBakerySubsystem(world.getMapper());
@@ -46,26 +47,21 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
//Max geometry: 1 gb
this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<19, (1L<<30)-1024);
this.nodeManager = new HierarchicalNodeManager(1<<21, this.sectionRenderer.getGeometryManager());
//Do something incredibly hacky, we dont need to keep the reference to this around, so just connect and discard
var positionFilterForwarder = new SectionPositionUpdateFilterer();
this.nodeManager = new HierarchicalNodeManager(1<<21, this.sectionRenderer.getGeometryManager(), positionFilterForwarder);
this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this.sectionBuildResultQueue::add, this.sectionRenderer.getGeometryManager() instanceof IUsesMeshlets);
positionFilterForwarder.setCallback(this.renderGen::enqueueTask);
this.traversal = new HierarchicalOcclusionTraverser(this.nodeManager, 512);
world.setDirtyCallback(this.nodeManager::sectionUpdate);
world.setDirtyCallback(positionFilterForwarder::maybeForward);
Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome);
world.getMapper().setBiomeCallback(this.modelService::addBiome);
for(int x = -1; x<=1;x++) {
for (int z = -1; z <= 1; z++) {
for (int y = -3; y <= 3; y++) {
this.renderGen.enqueueTask(0, x, y, z);
}
}
}
}
public void setup(Camera camera) {

View File

@@ -151,9 +151,15 @@ public class RenderGenerationService {
this.enqueueTask(lvl, x, y, z, (l,x1,y1,z1)->true);
}
public void enqueueTask(long position) {
this.enqueueTask(position, (l,x1,y1,z1)->true);
}
public void enqueueTask(int lvl, int x, int y, int z, TaskChecker checker) {
long ikey = WorldEngine.getWorldSectionId(lvl, x, y, z);
this.enqueueTask(WorldEngine.getWorldSectionId(lvl, x, y, z), checker);
}
public void enqueueTask(long ikey, TaskChecker checker) {
{
var cache = this.meshCache.getMesh(ikey);
if (cache != null) {
@@ -165,8 +171,8 @@ public class RenderGenerationService {
this.taskQueue.computeIfAbsent(ikey, key->{
this.taskCounter.release();
return new BuildTask(ikey, ()->{
if (checker.check(lvl, x, y, z)) {
return this.world.acquireIfExists(lvl, x, y, z);
if (checker.check(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey))) {
return this.world.acquireIfExists(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey));
} else {
return null;
}

View File

@@ -0,0 +1,75 @@
package me.cortex.voxy.client.core.rendering.building;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.common.world.WorldSection;
import java.util.function.LongConsumer;
public class SectionPositionUpdateFilterer {
private static final int SLICES = 1<<2;
private final LongOpenHashSet[] slices = new LongOpenHashSet[SLICES];
{
for (int i = 0; i < this.slices.length; i++) {
this.slices[i] = new LongOpenHashSet();
}
}
private LongConsumer forwardTo;
public void setCallback(LongConsumer forwardTo) {
if (this.forwardTo != null) {
throw new IllegalStateException();
}
this.forwardTo = forwardTo;
}
public boolean watch(int lvl, int x, int y, int z) {
return this.watch(WorldEngine.getWorldSectionId(lvl, x, y, z));
}
public boolean watch(long position) {
var set = this.slices[getSliceIndex(position)];
boolean added;
synchronized (set) {
added = set.add(position);
}
if (added) {
//If we added it, immediately invoke for an update
this.forwardTo.accept(position);
}
return added;
}
public boolean unwatch(int lvl, int x, int y, int z) {
return this.unwatch(WorldEngine.getWorldSectionId(lvl, x, y, z));
}
public boolean unwatch(long position) {
var set = this.slices[getSliceIndex(position)];
synchronized (set) {
return set.remove(position);
}
}
public void maybeForward(WorldSection section) {
this.maybeForward(section.key);
}
public void maybeForward(long position) {
var set = this.slices[getSliceIndex(position)];
boolean contains;
synchronized (set) {
contains = set.contains(position);
}
if (contains) {
this.forwardTo.accept(position);
}
}
private static int getSliceIndex(long value) {
value = (value ^ value >>> 30) * -4658895280553007687L;
value = (value ^ value >>> 27) * -7723592293110705685L;
return (int) ((value ^ value >>> 31)&(SLICES-1));
}
}

View File

@@ -1,7 +1,10 @@
package me.cortex.voxy.client.core.rendering.hierachical2;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.SectionPositionUpdateFilterer;
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
import me.cortex.voxy.common.util.HierarchicalBitSet;
import me.cortex.voxy.common.world.WorldSection;
@@ -15,18 +18,30 @@ public class HierarchicalNodeManager {
private final long[] localNodeData;
private final AbstractSectionGeometryManager geometryManager;
private final HierarchicalBitSet allocationSet;
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager) {
private final Long2IntOpenHashMap activeSectionMap = new Long2IntOpenHashMap();
private final SectionPositionUpdateFilterer updateFilterer;
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionPositionUpdateFilterer updateFilterer) {
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.updateFilterer = updateFilterer;
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
this.maxNodeCount = maxNodeCount;
this.localNodeData = new long[maxNodeCount*4];
this.geometryManager = geometryManager;
for(int x = -1; x<=1;x++) {
for (int z = -1; z <= 1; z++) {
for (int y = -3; y <= 3; y++) {
updateFilterer.watch(0,x,y,z);
}
}
}
}
public void processRequestQueue(int count, long ptr) {
@@ -44,9 +59,4 @@ public class HierarchicalNodeManager {
section.free();
}
}
//Called when a section is updated in the world engine
public void sectionUpdate(WorldSection section) {
}
}

View File

@@ -4,5 +4,10 @@ package me.cortex.voxy.client.core.rendering.hierachical2;
class LeafExpansionRequest {
//Child states contain micrometadata in the top bits
// such as isEmpty, and isEmptyButEventuallyHasNonEmptyChild
private final long nodePos;
private final int[] childStates = new int[8];
LeafExpansionRequest(long nodePos) {
this.nodePos = nodePos;
}
}