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.model.ModelStore;
|
||||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
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.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.HierarchicalNodeManager;
|
||||||
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
||||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionRenderer;
|
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.DownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import me.cortex.voxy.common.world.WorldSection;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
|
|
||||||
import java.util.Arrays;
|
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<>();
|
private final ConcurrentLinkedDeque<BuiltSection> sectionBuildResultQueue = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
|
|
||||||
public RenderService(WorldEngine world) {
|
public RenderService(WorldEngine world) {
|
||||||
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
||||||
|
|
||||||
@@ -46,26 +47,21 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
|||||||
//Max geometry: 1 gb
|
//Max geometry: 1 gb
|
||||||
this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<19, (1L<<30)-1024);
|
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.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
|
||||||
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this.sectionBuildResultQueue::add, this.sectionRenderer.getGeometryManager() instanceof IUsesMeshlets);
|
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);
|
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);
|
Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome);
|
||||||
world.getMapper().setBiomeCallback(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) {
|
public void setup(Camera camera) {
|
||||||
|
|||||||
@@ -151,9 +151,15 @@ public class RenderGenerationService {
|
|||||||
this.enqueueTask(lvl, x, y, z, (l,x1,y1,z1)->true);
|
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) {
|
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);
|
var cache = this.meshCache.getMesh(ikey);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
@@ -165,8 +171,8 @@ public class RenderGenerationService {
|
|||||||
this.taskQueue.computeIfAbsent(ikey, key->{
|
this.taskQueue.computeIfAbsent(ikey, key->{
|
||||||
this.taskCounter.release();
|
this.taskCounter.release();
|
||||||
return new BuildTask(ikey, ()->{
|
return new BuildTask(ikey, ()->{
|
||||||
if (checker.check(lvl, x, y, z)) {
|
if (checker.check(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey))) {
|
||||||
return this.world.acquireIfExists(lvl, x, y, z);
|
return this.world.acquireIfExists(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
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;
|
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.BuiltSection;
|
||||||
|
import me.cortex.voxy.client.core.rendering.building.SectionPositionUpdateFilterer;
|
||||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
||||||
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
||||||
import me.cortex.voxy.common.world.WorldSection;
|
import me.cortex.voxy.common.world.WorldSection;
|
||||||
@@ -15,18 +18,30 @@ public class HierarchicalNodeManager {
|
|||||||
private final long[] localNodeData;
|
private final long[] localNodeData;
|
||||||
private final AbstractSectionGeometryManager geometryManager;
|
private final AbstractSectionGeometryManager geometryManager;
|
||||||
private final HierarchicalBitSet allocationSet;
|
private final HierarchicalBitSet allocationSet;
|
||||||
|
private final Long2IntOpenHashMap activeSectionMap = new Long2IntOpenHashMap();
|
||||||
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager) {
|
private final SectionPositionUpdateFilterer updateFilterer;
|
||||||
|
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionPositionUpdateFilterer updateFilterer) {
|
||||||
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
|
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
|
||||||
throw new IllegalArgumentException("Max node count must be a power of 2");
|
throw new IllegalArgumentException("Max node count must be a power of 2");
|
||||||
}
|
}
|
||||||
if (maxNodeCount>(1<<24)) {
|
if (maxNodeCount>(1<<24)) {
|
||||||
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
|
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
|
||||||
}
|
}
|
||||||
|
this.updateFilterer = updateFilterer;
|
||||||
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
|
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
|
||||||
this.maxNodeCount = maxNodeCount;
|
this.maxNodeCount = maxNodeCount;
|
||||||
this.localNodeData = new long[maxNodeCount*4];
|
this.localNodeData = new long[maxNodeCount*4];
|
||||||
this.geometryManager = geometryManager;
|
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) {
|
public void processRequestQueue(int count, long ptr) {
|
||||||
@@ -44,9 +59,4 @@ public class HierarchicalNodeManager {
|
|||||||
section.free();
|
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 {
|
class LeafExpansionRequest {
|
||||||
//Child states contain micrometadata in the top bits
|
//Child states contain micrometadata in the top bits
|
||||||
// such as isEmpty, and isEmptyButEventuallyHasNonEmptyChild
|
// such as isEmpty, and isEmptyButEventuallyHasNonEmptyChild
|
||||||
|
private final long nodePos;
|
||||||
private final int[] childStates = new int[8];
|
private final int[] childStates = new int[8];
|
||||||
|
|
||||||
|
LeafExpansionRequest(long nodePos) {
|
||||||
|
this.nodePos = nodePos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user