Update forwarding and checking
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user