Working even better

This commit is contained in:
mcrcortex
2024-07-15 20:40:13 +10:00
parent 4cbd7af3d0
commit 0ff2db1881
7 changed files with 80 additions and 9 deletions

View File

@@ -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);
//} //}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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
} }

View File

@@ -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) {}

View File

@@ -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 {