Working even better
This commit is contained in:
@@ -7,6 +7,7 @@ import me.cortex.voxy.client.core.model.ModelManager;
|
|||||||
import me.cortex.voxy.client.core.rendering.*;
|
import me.cortex.voxy.client.core.rendering.*;
|
||||||
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.post.PostProcessing;
|
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
import me.cortex.voxy.client.core.util.IrisUtil;
|
import me.cortex.voxy.client.core.util.IrisUtil;
|
||||||
import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
@@ -212,6 +213,9 @@ public class VoxelCore {
|
|||||||
// since they are AABBS crossing the normal is impossible without one of the axis being equal
|
// since they are AABBS crossing the normal is impossible without one of the axis being equal
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
System.out.println("Flushing download stream");
|
||||||
|
DownloadStream.INSTANCE.flushWaitClear();
|
||||||
|
|
||||||
//if (Thread.currentThread() != this.shutdownThread) {
|
//if (Thread.currentThread() != this.shutdownThread) {
|
||||||
// Runtime.getRuntime().removeShutdownHook(this.shutdownThread);
|
// Runtime.getRuntime().removeShutdownHook(this.shutdownThread);
|
||||||
//}
|
//}
|
||||||
|
|||||||
@@ -14,17 +14,21 @@ import me.cortex.voxy.client.core.rendering.hierarchical.INodeInteractor;
|
|||||||
import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager;
|
import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import me.cortex.voxy.common.world.WorldSection;
|
import me.cortex.voxy.common.world.WorldSection;
|
||||||
import me.cortex.voxy.common.world.other.Mapper;
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.client.render.Frustum;
|
import net.minecraft.client.render.Frustum;
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.ARBDirectStateAccess.glTextureParameteri;
|
import static org.lwjgl.opengl.ARBDirectStateAccess.glTextureParameteri;
|
||||||
@@ -52,6 +56,12 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
|
|||||||
private final GlBuffer renderSections = new GlBuffer(100_000 * 4 + 4).zero();
|
private final GlBuffer renderSections = new GlBuffer(100_000 * 4 + 4).zero();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final ConcurrentLinkedDeque<Mapper.StateEntry> blockStateUpdates = new ConcurrentLinkedDeque<>();
|
||||||
|
private final ConcurrentLinkedDeque<Mapper.BiomeEntry> biomeUpdates = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
|
protected final ConcurrentLinkedDeque<BuiltSection> buildResults = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
private final ModelManager modelManager;
|
private final ModelManager modelManager;
|
||||||
private RenderGenerationService sectionGenerationService;
|
private RenderGenerationService sectionGenerationService;
|
||||||
private Consumer<BuiltSection> resultConsumer;
|
private Consumer<BuiltSection> resultConsumer;
|
||||||
@@ -72,7 +82,12 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestMesh(long pos) {
|
public void requestMesh(long pos) {
|
||||||
System.err.println("Request: " + pos);
|
Gl46HierarchicalRenderer.this.sectionGenerationService.enqueueTask(
|
||||||
|
WorldEngine.getLevel(pos),
|
||||||
|
WorldEngine.getX(pos),
|
||||||
|
WorldEngine.getY(pos),
|
||||||
|
WorldEngine.getZ(pos)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,11 +99,39 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupRender(Frustum frustum, Camera camera) {
|
public void setupRender(Frustum frustum, Camera camera) {
|
||||||
|
{
|
||||||
|
boolean didHaveBiomeChange = false;
|
||||||
|
|
||||||
|
//Do any BiomeChanges
|
||||||
|
while (!this.biomeUpdates.isEmpty()) {
|
||||||
|
var update = this.biomeUpdates.pop();
|
||||||
|
var biomeReg = MinecraftClient.getInstance().world.getRegistryManager().get(RegistryKeys.BIOME);
|
||||||
|
this.modelManager.addBiome(update.id, biomeReg.get(Identifier.of(update.biome)));
|
||||||
|
didHaveBiomeChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (didHaveBiomeChange) {
|
||||||
|
UploadStream.INSTANCE.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxUpdatesPerFrame = 40;
|
||||||
|
|
||||||
|
//Do any BlockChanges
|
||||||
|
while ((!this.blockStateUpdates.isEmpty()) && (maxUpdatesPerFrame-- > 0)) {
|
||||||
|
var update = this.blockStateUpdates.pop();
|
||||||
|
this.modelManager.addEntry(update.id, update.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderFarAwayOpaque(Gl46HierarchicalViewport viewport) {
|
public void renderFarAwayOpaque(Gl46HierarchicalViewport viewport) {
|
||||||
|
//Process all the build results
|
||||||
|
while (!this.buildResults.isEmpty()) {
|
||||||
|
this.resultConsumer.accept(this.buildResults.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Render terrain from previous frame (renderSections)
|
//Render terrain from previous frame (renderSections)
|
||||||
|
|
||||||
|
|
||||||
@@ -121,12 +164,12 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBlockState(Mapper.StateEntry stateEntry) {
|
public void addBlockState(Mapper.StateEntry stateEntry) {
|
||||||
|
this.blockStateUpdates.add(stateEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBiome(Mapper.BiomeEntry biomeEntry) {
|
public void addBiome(Mapper.BiomeEntry biomeEntry) {
|
||||||
|
this.biomeUpdates.add(biomeEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -134,7 +177,7 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processBuildResult(BuiltSection section) {
|
public void processBuildResult(BuiltSection section) {
|
||||||
|
this.buildResults.add(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ import java.util.function.ToIntFunction;
|
|||||||
|
|
||||||
//TODO: Add a render cache
|
//TODO: Add a render cache
|
||||||
public class RenderGenerationService {
|
public class RenderGenerationService {
|
||||||
|
|
||||||
public interface TaskChecker {boolean check(int lvl, int x, int y, int z);}
|
public interface TaskChecker {boolean check(int lvl, int x, int y, int z);}
|
||||||
private record BuildTask(Supplier<WorldSection> sectionSupplier) {}
|
private record BuildTask(long position, Supplier<WorldSection> sectionSupplier) {}
|
||||||
|
|
||||||
private volatile boolean running = true;
|
private volatile boolean running = true;
|
||||||
private final Thread[] workers;
|
private final Thread[] workers;
|
||||||
@@ -60,6 +59,7 @@ public class RenderGenerationService {
|
|||||||
}
|
}
|
||||||
var section = task.sectionSupplier.get();
|
var section = task.sectionSupplier.get();
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
|
this.resultConsumer.accept(new BuiltSection(task.position));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
section.assertNotFree();
|
section.assertNotFree();
|
||||||
@@ -130,7 +130,7 @@ public class RenderGenerationService {
|
|||||||
synchronized (this.taskQueue) {
|
synchronized (this.taskQueue) {
|
||||||
this.taskQueue.computeIfAbsent(ikey, key->{
|
this.taskQueue.computeIfAbsent(ikey, key->{
|
||||||
this.taskCounter.release();
|
this.taskCounter.release();
|
||||||
return new BuildTask(()->{
|
return new BuildTask(ikey, ()->{
|
||||||
if (checker.check(lvl, x, y, z)) {
|
if (checker.check(lvl, x, y, z)) {
|
||||||
return this.world.acquireIfExists(lvl, x, y, z);
|
return this.world.acquireIfExists(lvl, x, y, z);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ public class MeshManager {
|
|||||||
|
|
||||||
//Varient of uploadMesh that releases the previous mesh at the same time, this is a performance optimization
|
//Varient of uploadMesh that releases the previous mesh at the same time, this is a performance optimization
|
||||||
public int uploadReplaceMesh(int old, BuiltSection section) {
|
public int uploadReplaceMesh(int old, BuiltSection section) {
|
||||||
return -1;
|
section.free();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeMesh(int mesh) {
|
public void removeMesh(int mesh) {
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ public class NodeManager {
|
|||||||
if ((msk&(1<<i))!=0) {
|
if ((msk&(1<<i))!=0) {
|
||||||
//It means the section actually exists, so add and upload it
|
//It means the section actually exists, so add and upload it
|
||||||
// aswell as add it to the mapping + push the node
|
// aswell as add it to the mapping + push the node
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//The section was empty, so just remove/skip it
|
//The section was empty, so just remove/skip it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ public class DownloadStream {
|
|||||||
if (size > Integer.MAX_VALUE) {
|
if (size > Integer.MAX_VALUE) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
if (size <= 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (destOffset+size > buffer.size()) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
long addr;
|
long addr;
|
||||||
if (this.caddr == -1 || !this.allocationArena.expand(this.caddr, (int) size)) {
|
if (this.caddr == -1 || !this.allocationArena.expand(this.caddr, (int) size)) {
|
||||||
@@ -125,6 +131,20 @@ public class DownloadStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Synchonize force flushes everything
|
||||||
|
public void flushWaitClear() {
|
||||||
|
this.tick();
|
||||||
|
var fence = new GlFence();
|
||||||
|
glFinish();
|
||||||
|
while (!fence.signaled())
|
||||||
|
Thread.onSpinWait();
|
||||||
|
fence.free();
|
||||||
|
this.tick();
|
||||||
|
if (!this.frames.isEmpty()) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private record DownloadFrame(GlFence fence, LongArrayList allocations, ArrayList<DownloadData> data) {}
|
private record DownloadFrame(GlFence fence, LongArrayList allocations, ArrayList<DownloadData> data) {}
|
||||||
private record DownloadData(GlBuffer target, long downloadStreamOffset, long targetOffset, long size, DownloadResultConsumer resultConsumer) {}
|
private record DownloadData(GlBuffer target, long downloadStreamOffset, long targetOffset, long size, DownloadResultConsumer resultConsumer) {}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,8 @@ void main() {
|
|||||||
} else {
|
} else {
|
||||||
//It is visible, TODO: maybe do a more detailed hiz test? (or make it so that )
|
//It is visible, TODO: maybe do a more detailed hiz test? (or make it so that )
|
||||||
|
|
||||||
if (shouldDecend()) {
|
//Only decend if not a root node
|
||||||
|
if (node.lodLevel!=0 && shouldDecend()) {
|
||||||
if (hasChildren(node)) {
|
if (hasChildren(node)) {
|
||||||
enqueueChildren(node);
|
enqueueChildren(node);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user