Removed caching rings, tinkered with model bakery, tweeked upload counts, moved inital ring fill offthread

This commit is contained in:
mcrcortex
2024-02-16 17:50:58 +10:00
parent 6ac4071f1b
commit 8293f0cfdd
9 changed files with 105 additions and 49 deletions

View File

@@ -8,7 +8,7 @@ yarn_mappings=1.20.4+build.1
loader_version=0.15.0 loader_version=0.15.0
# Mod Properties # Mod Properties
mod_version = 0.0.7-alpha mod_version = 0.0.8-alpha
maven_group = me.cortex maven_group = me.cortex
archives_base_name = voxy archives_base_name = voxy

View File

@@ -8,6 +8,8 @@ import me.cortex.voxy.client.core.rendering.RenderTracker;
import me.cortex.voxy.client.core.util.RingUtil; import me.cortex.voxy.client.core.util.RingUtil;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import java.util.stream.IntStream;
//Can use ring logic //Can use ring logic
// i.e. when a player moves the rings of each lod change (how it was doing in the original attempt) // i.e. when a player moves the rings of each lod change (how it was doing in the original attempt)
// also have it do directional quad culling and rebuild the chunk if needed (this shouldent happen very often) (the reason is to significantly reduce draw calls) // also have it do directional quad culling and rebuild the chunk if needed (this shouldent happen very often) (the reason is to significantly reduce draw calls)
@@ -26,8 +28,8 @@ public class DistanceTracker {
this.cacheLoadRings = new TransitionRing2D[lodRingScales.length]; this.cacheLoadRings = new TransitionRing2D[lodRingScales.length];
this.cacheUnloadRings = new TransitionRing2D[lodRingScales.length]; this.cacheUnloadRings = new TransitionRing2D[lodRingScales.length];
this.tracker = tracker; this.tracker = tracker;
this.minYSection = MinecraftClient.getInstance().world.getBottomSectionCoord()/2; this.minYSection = MinecraftClient.getInstance().world.getBottomSectionCoord()/2;//-128;
this.maxYSection = MinecraftClient.getInstance().world.getTopSectionCoord()/2; this.maxYSection = MinecraftClient.getInstance().world.getTopSectionCoord()/2;//128;
//The rings 0+ start at 64 vanilla rd, no matter what the game is set at, that is if the game is set to 32 rd //The rings 0+ start at 64 vanilla rd, no matter what the game is set at, that is if the game is set to 32 rd
@@ -40,18 +42,20 @@ public class DistanceTracker {
//TODO:FIXME i think the radius is wrong and (lodRingScales[i]) needs to be (lodRingScales[i]<<1) since the transition ring (the thing above) //TODO:FIXME i think the radius is wrong and (lodRingScales[i]) needs to be (lodRingScales[i]<<1) since the transition ring (the thing above)
// acts on LoD level + 1 // acts on LoD level + 1
this.cacheLoadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheLoadDistance, (x, z) -> {
//When entering a cache ring, trigger a mesh op and inject into cache //TODO: check this is actually working lmao and make it generate parent level lods on the exit instead of entry so it looks correct when flying backwards
for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { //this.cacheLoadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheLoadDistance, (x, z) -> {
this.tracker.addCache(capRing, x, y, z); // //When entering a cache ring, trigger a mesh op and inject into cache
} // for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) {
}, (x, z) -> {}); // this.tracker.addCache(capRing, x, y, z);
this.cacheUnloadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheUnloadDistance, (x, z) -> {}, (x, z) -> { // }
//When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position //}, (x, z) -> {});
for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { //this.cacheUnloadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheUnloadDistance, (x, z) -> {}, (x, z) -> {
this.tracker.removeCache(capRing, x, y, z); // //When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position
} // for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) {
}); // this.tracker.removeCache(capRing, x, y, z);
// }
//});
} }
} }
@@ -75,36 +79,64 @@ public class DistanceTracker {
// the lod sections // the lod sections
public void setCenter(int x, int y, int z) { public void setCenter(int x, int y, int z) {
for (var ring : this.cacheLoadRings) { for (var ring : this.cacheLoadRings) {
ring.update(x, z); if (ring!=null)
ring.update(x, z);
} }
for (var ring : this.loDRings) { for (var ring : this.loDRings) {
ring.update(x, z); ring.update(x, z);
} }
for (var ring : this.cacheUnloadRings) { for (var ring : this.cacheUnloadRings) {
ring.update(x, z); if (ring!=null)
ring.update(x, z);
} }
} }
public void init(int x, int z) { public void init(int x, int z) {
//Radius of chunks to enqueue
int SIZE = 128;
//Insert highest LOD level
for (int ox = -SIZE; ox <= SIZE; ox++) {
for (int oz = -SIZE; oz <= SIZE; oz++) {
this.inc(4, (x>>(5+this.loDRings.length)) + ox, (z>>(5+this.loDRings.length)) + oz);
}
}
for (var ring : this.cacheLoadRings) { for (var ring : this.cacheLoadRings) {
ring.fill(x, z); if (ring != null)
ring.setCenter(x, z);
} }
for (int i = this.loDRings.length-1; 0 <= i; i--) { for (var ring : this.cacheUnloadRings) {
if (this.loDRings[i] != null) { if (ring != null)
this.loDRings[i].fill(x, z); ring.setCenter(x, z);
}
} }
for (var ring : this.loDRings) {
if (ring != null)
ring.setCenter(x, z);
}
var thread = new Thread(()-> {
//Radius of chunks to enqueue
int SIZE = 128;
//Insert highest LOD level
for (int ox = -SIZE; ox <= SIZE; ox++) {
for (int oz = -SIZE; oz <= SIZE; oz++) {
this.inc(4, (x >> (5 + this.loDRings.length)) + ox, (z >> (5 + this.loDRings.length)) + oz);
}
}
for (var ring : this.cacheLoadRings) {
if (ring != null)
ring.fill(x, z);
}
for (var ring : this.cacheUnloadRings) {
if (ring != null)
ring.fill(x, z);
}
for (int i = this.loDRings.length - 1; 0 <= i; i--) {
if (this.loDRings[i] != null) {
this.loDRings[i].fill(x, z);
}
}
});
thread.setName("LoD Ring Initializer");
thread.start();
//TODO: FIXME: need to destory on shutdown
} }
@@ -248,6 +280,7 @@ public class DistanceTracker {
int r2 = this.radius*this.radius; int r2 = this.radius*this.radius;
for (int a = -this.radius; a <= this.radius; a++) { for (int a = -this.radius; a <= this.radius; a++) {
//IntStream.range(-this.radius, this.radius+1).parallel().forEach(a->{
int b = (int) Math.floor(Math.sqrt(r2-(a*a))); int b = (int) Math.floor(Math.sqrt(r2-(a*a)));
for (int c = -b; c <= b; c++) { for (int c = -b; c <= b; c++) {
this.enter.callback(a + cx, c + cz); this.enter.callback(a + cx, c + cz);
@@ -261,8 +294,12 @@ public class DistanceTracker {
outsideCallback.callback(a + cx, c + cz); outsideCallback.callback(a + cx, c + cz);
} }
} }
} }//);
}
public void setCenter(int x, int z) {
int cx = x>>this.shiftSize;
int cz = z>>this.shiftSize;
this.currentX = cx; this.currentX = cx;
this.currentZ = cz; this.currentZ = cz;
this.lastUpdateX = x + (((int)(Math.random()*4))<<(this.shiftSize-4)); this.lastUpdateX = x + (((int)(Math.random()*4))<<(this.shiftSize-4));

View File

@@ -347,7 +347,7 @@ public class ModelManager {
public void addBiome(int id, Biome biome) { public void addBiome(int id, Biome biome) {
this.biomes.add(biome); this.biomes.add(biome);
if (this.biomes.size()-1 != id) { if (this.biomes.size()-1 != id) {
throw new IllegalStateException("Biome ordering not consistent with biome id"); throw new IllegalStateException("Biome ordering not consistent with biome id for biome " + biome + " expected id: " + (this.biomes.size()-1) + " got id: " + id);
} }
int i = 0; int i = 0;

View File

@@ -164,7 +164,8 @@ public class ModelTextureBakery {
this.rasterShader.bind(); this.rasterShader.bind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")).getGlId()); int texId = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")).getGlId();
glBindTexture(GL_TEXTURE_2D, texId);
GlUniform.uniform1(0, 0); GlUniform.uniform1(0, 0);
var faces = new ColourDepthTextureData[FACE_VIEWS.size()]; var faces = new ColourDepthTextureData[FACE_VIEWS.size()];
@@ -192,6 +193,23 @@ public class ModelTextureBakery {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE);
//if (state.hasBlockEntity() && state.getBlock() == Blocks.CHEST) {
// //TODO: finish BlockEntity raster
// var entity = ((BlockEntityProvider)state.getBlock()).createBlockEntity(BlockPos.ORIGIN, state);
// var renderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(entity);
// if (renderer != null) {
// entity.setWorld(MinecraftClient.getInstance().world);
// renderer.render(entity, 0.0f, new MatrixStack(), (layer) -> {
// //glBindTexture(GL_TEXTURE_2D);
// return vc;
// }, 0, 0);
// }
// entity.markRemoved();
//}
if (!renderFluid) { if (!renderFluid) {
renderQuads(vc, state, model, new MatrixStack(), randomValue); renderQuads(vc, state, model, new MatrixStack(), randomValue);
} else { } else {
@@ -260,15 +278,6 @@ public class ModelTextureBakery {
BufferRenderer.draw(vc.end()); BufferRenderer.draw(vc.end());
if (state.hasBlockEntity()) {
//TODO: finish BlockEntity raster
//var entity = ((BlockEntityProvider)state).createBlockEntity(BlockPos.ORIGIN, state);
//var renderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(entity);
//renderer.render();
//entity.markRemoved();
}
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
int[] colourData = new int[this.width*this.height]; int[] colourData = new int[this.width*this.height];
int[] depthData = new int[this.width*this.height]; int[] depthData = new int[this.width*this.height];

View File

@@ -95,7 +95,8 @@ public class TextureUtils {
// due to this and the unsigned bullshit, i believe the depth value needs to get multiplied by 2 // due to this and the unsigned bullshit, i believe the depth value needs to get multiplied by 2
depthF *= 2; depthF *= 2;
if (depthF > 1.00001f) { if (depthF > 1.00001f) {
throw new IllegalArgumentException("Depth greater than 1"); System.err.println("Warning: Depth greater than 1");
depthF = 1.0f;
} }
return depthF; return depthF;
} }

View File

@@ -105,7 +105,7 @@ public abstract class AbstractFarWorldRenderer {
UploadStream.INSTANCE.commit(); UploadStream.INSTANCE.commit();
} }
int maxUpdatesPerFrame = 30; int maxUpdatesPerFrame = 10;
//Do any BlockChanges //Do any BlockChanges
while ((!this.blockStateUpdates.isEmpty()) && (maxUpdatesPerFrame-- > 0)) { while ((!this.blockStateUpdates.isEmpty()) && (maxUpdatesPerFrame-- > 0)) {

View File

@@ -141,8 +141,8 @@ public class RenderTracker {
//Enqueues a renderTask for a section to cache the result //Enqueues a renderTask for a section to cache the result
public void addCache(int lvl, int x, int y, int z) { public void addCache(int lvl, int x, int y, int z) {
//this.renderGen.markCache(lvl, x, y, z); this.renderGen.markCache(lvl, x, y, z);
//this.renderGen.enqueueTask(lvl, x, y, z, ((lvl1, x1, y1, z1) -> true));//TODO: replace the true identity lambda with a callback check to the render cache this.renderGen.enqueueTask(lvl, x, y, z, ((lvl1, x1, y1, z1) -> true));//TODO: replace the true identity lambda with a callback check to the render cache
} }
//Removes the position from the cache //Removes the position from the cache

View File

@@ -2,6 +2,8 @@ package me.cortex.voxy.client.core.rendering.building;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
//TODO: Have a second level disk cache
//TODO: instead of storing duplicate render geometry between here and gpu memory //TODO: instead of storing duplicate render geometry between here and gpu memory
// when a section is unloaded from the gpu, put it into a download stream and recover the BuiltSection // when a section is unloaded from the gpu, put it into a download stream and recover the BuiltSection
// and put that into the cache, then remove the uploaded mesh from the cache // and put that into the cache, then remove the uploaded mesh from the cache
@@ -24,7 +26,9 @@ public class BuiltSectionMeshCache {
//Returns true if the mesh was used, (this is so the parent method can free mesh object) //Returns true if the mesh was used, (this is so the parent method can free mesh object)
public boolean putMesh(BuiltSection mesh) { public boolean putMesh(BuiltSection mesh) {
var mesh2 = this.renderCache.computeIfPresent(mesh.position, (id, value) -> { var mesh2 = this.renderCache.computeIfPresent(mesh.position, (id, value) -> {
value.free(); if (value != HOLDER) {
value.free();
}
return mesh; return mesh;
}); });
return mesh2 == mesh; return mesh2 == mesh;

View File

@@ -61,6 +61,11 @@ public class RenderGenerationService {
try { try {
mesh = factory.generateMesh(section); mesh = factory.generateMesh(section);
} catch (IdNotYetComputedException e) { } catch (IdNotYetComputedException e) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
//We need to reinsert the build task into the queue //We need to reinsert the build task into the queue
//System.err.println("Render task failed to complete due to un-computed client id"); //System.err.println("Render task failed to complete due to un-computed client id");
synchronized (this.taskQueue) { synchronized (this.taskQueue) {