From 79cfe99e8d467aa7634c3c3e5f56bbe82d07672b Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:59:51 +1000 Subject: [PATCH] Improves perf alot --- gradle.properties | 4 +- .../cortex/voxelmon/core/DistanceTracker.java | 31 +++- .../me/cortex/voxelmon/core/VoxelCore.java | 5 + .../rendering/building/RenderDataFactory.java | 70 ++++--- .../cortex/voxelmon/core/util/Mesher2D.java | 141 +++++++------- .../cortex/voxelmon/core/util/Mesher2Dv2.java | 175 ------------------ .../voxelmon/core/world/WorldSection.java | 6 + .../voxelmon/core/world/other/Mapper.java | 10 +- .../voxelmon/shaders/lod/gl46/quads.vert | 32 ++-- 9 files changed, 179 insertions(+), 295 deletions(-) delete mode 100644 src/main/java/me/cortex/voxelmon/core/util/Mesher2Dv2.java diff --git a/gradle.properties b/gradle.properties index 6f5823db..491508e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,11 +5,11 @@ org.gradle.jvmargs=-Xmx1G # check these on https://modmuss50.me/fabric.html minecraft_version=1.20.4 yarn_mappings=1.20.4+build.1 -loader_version=0.14.22 +loader_version=0.15.0 # Mod Properties mod_version = 0.0.1 maven_group = me.cortex archives_base_name = zenith -fabric_version=0.89.0+1.20.2 +fabric_version=0.91.1+1.20.4 diff --git a/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java b/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java index 4f54872c..c1fea825 100644 --- a/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java +++ b/src/main/java/me/cortex/voxelmon/core/DistanceTracker.java @@ -3,6 +3,7 @@ package me.cortex.voxelmon.core; //Contains the logic to determine what is loaded and at what LoD level, dispatches render changes // also determines what faces are built etc +import it.unimi.dsi.fastutil.Arrays; import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import me.cortex.voxelmon.core.rendering.AbstractFarWorldRenderer; @@ -22,7 +23,7 @@ public class DistanceTracker { private final TransitionRing2D[] rings; private final RenderTracker tracker; public DistanceTracker(RenderTracker tracker, int rings) { - this.rings = new TransitionRing2D[rings+1]; + this.rings = new TransitionRing2D[rings]; this.tracker = tracker; //NOTE: This is in our render distance units, to convert to chunks at lvl 0 multiply by 2 @@ -48,13 +49,13 @@ public class DistanceTracker { } private void inc(int lvl, int x, int z) { - for (int y = -2>>lvl; y < 10>>lvl; y++) { + for (int y = -2>>lvl; y <= 10>>lvl; y++) { this.tracker.inc(lvl, x, y, z); } } private void dec(int lvl, int x, int z) { - for (int y = -2>>lvl; y < 10>>lvl; y++) { + for (int y = -2>>lvl; y <= 10>>lvl; y++) { this.tracker.dec(lvl, x, y, z); } } @@ -73,6 +74,14 @@ public class DistanceTracker { } } + public void init(int x, int z) { + for (int i = this.rings.length-1; 0 <= i; i--) { + if (this.rings[i] != null) { + this.rings[i].fill(x, z); + } + } + } + //TODO: add a new class thing that can track the central axis point so that // geometry can be rebuilt with new flags with correct facing geometry built @@ -204,8 +213,22 @@ public class DistanceTracker { ops.clear(); } - public void fill() { + public void fill(int x, int z) { + int cx = x>>this.shiftSize; + int cz = z>>this.shiftSize; + int r2 = this.radius*this.radius; + for (int a = -this.radius; a <= this.radius; a++) { + int b = (int) Math.floor(Math.sqrt(r2-(a*a))); + for (int c = -b; c <= b; c++) { + this.enter.callback(a + cx, c + cz); + } + } + + this.currentX = cx; + this.currentZ = cz; + this.lastUpdateX = x; + this.lastUpdateZ = z; } } } diff --git a/src/main/java/me/cortex/voxelmon/core/VoxelCore.java b/src/main/java/me/cortex/voxelmon/core/VoxelCore.java index b6621932..4787410e 100644 --- a/src/main/java/me/cortex/voxelmon/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxelmon/core/VoxelCore.java @@ -148,7 +148,12 @@ public class VoxelCore { this.world.ingestService.enqueueIngest(worldChunk); } + boolean firstTime = true; public void renderSetup(Frustum frustum, Camera camera) { + if (this.firstTime) { + this.distanceTracker.init(camera.getBlockPos().getX(), camera.getBlockPos().getZ()); + this.firstTime = false; + } this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ()); this.renderer.setupRender(frustum, camera); } diff --git a/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java index 569f7215..481f8807 100644 --- a/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java +++ b/src/main/java/me/cortex/voxelmon/core/rendering/building/RenderDataFactory.java @@ -3,7 +3,6 @@ package me.cortex.voxelmon.core.rendering.building; import it.unimi.dsi.fastutil.longs.LongArrayList; import me.cortex.voxelmon.core.util.MemoryBuffer; import me.cortex.voxelmon.core.util.Mesher2D; -import me.cortex.voxelmon.core.util.Mesher2Dv2; import me.cortex.voxelmon.core.world.WorldEngine; import me.cortex.voxelmon.core.world.WorldSection; import me.cortex.voxelmon.core.world.other.Mapper; @@ -12,9 +11,12 @@ import org.lwjgl.system.MemoryUtil; public class RenderDataFactory { - private final Mesher2Dv2 mesher = new Mesher2Dv2(5,15);//15 + private final Mesher2D mesher = new Mesher2D(5,15);//15 private final LongArrayList outData = new LongArrayList(1000); private final WorldEngine world; + private final long[] sectionCache = new long[32*32*32]; + private final long[] connectedSectionCache = new long[32*32*32]; + public RenderDataFactory(WorldEngine world) { this.world = world; } @@ -39,8 +41,8 @@ public class RenderDataFactory { // return new BuiltSectionGeometry(section.getKey(), null, null); //} - - var data = section.copyData(); + section.copyDataTo(this.sectionCache); + var data = this.sectionCache; long[] connectedData = null; int dirId = Direction.UP.getId(); @@ -65,7 +67,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x, section.y + 1, section.z); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(x, 0, z)]; @@ -77,9 +80,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 1, y, quad)); } } @@ -108,7 +112,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x + 1, section.y, section.z); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(0, y, z)]; @@ -120,9 +125,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 5, x, quad)); } } @@ -151,7 +157,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z + 1); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(x, y, 0)]; @@ -163,9 +170,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 3, z, quad)); } } @@ -194,7 +202,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x - 1, section.y, section.z); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(31, y, z)]; @@ -206,9 +215,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 4, x, quad)); } } @@ -237,7 +247,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z - 1); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(x, y, 31)]; @@ -249,9 +260,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 2, z, quad)); } } @@ -280,7 +292,8 @@ public class RenderDataFactory { //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies if (connectedData == null) { var connectedSection = this.world.acquire(section.lvl, section.x, section.y - 1, section.z); - connectedData = connectedSection.copyData(); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; connectedSection.release(); } up = connectedData[WorldSection.getIndex(x, 31, z)]; @@ -292,9 +305,10 @@ public class RenderDataFactory { } } - var quads = this.mesher.process(); - for (int i = 0; i < quads.length; i++) { - var quad = quads[i]; + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; this.outData.add(QuadFormat.encode(null, this.mesher.getDataFromQuad(quad), 0, y, quad)); } } diff --git a/src/main/java/me/cortex/voxelmon/core/util/Mesher2D.java b/src/main/java/me/cortex/voxelmon/core/util/Mesher2D.java index 84947f12..ac78525c 100644 --- a/src/main/java/me/cortex/voxelmon/core/util/Mesher2D.java +++ b/src/main/java/me/cortex/voxelmon/core/util/Mesher2D.java @@ -8,13 +8,13 @@ public class Mesher2D { private final int size; private final int maxSize; private final long[] data; - private final BitSet meshed; + private final BitSet setset; private int[] quadCache; public Mesher2D(int sizeBits, int maxSize) { this.size = sizeBits; this.maxSize = maxSize; this.data = new long[1<<(sizeBits<<1)]; - this.meshed = new BitSet(1<<(sizeBits<<1)); + this.setset = new BitSet(1<<(sizeBits<<1)); this.quadCache = new int[128]; } @@ -27,7 +27,9 @@ public class Mesher2D { } public Mesher2D put(int x, int z, long data) { - this.data[this.getIdx(x, z)] = data; + int idx = this.getIdx(x, z); + this.data[idx] = data; + this.setset.set(idx); return this; } @@ -54,90 +56,91 @@ public class Mesher2D { private boolean canMerge(int x, int z, long match) { int id = this.getIdx(x, z); - return this.data[id] == match && !this.meshed.get(id); + return this.setset.get(id) && this.data[id] == match; } - public int[] process() { - //TODO: replace this loop with a loop over a bitset of data that has been put into the mesher, have the this.meshed be removed - // and just clear the databitset when its meshed - + //Returns the number of compacted quads + public int process() { int[] quads = this.quadCache; int idxCount = 0; //TODO: add different strategies/ways to mesh - for (int z = 0; z < 1<>>this.size)&M; + + boolean ex = x != ((1< this.maxSize || endX+1 == (1 << this.size) - 1) { + ex = false; + } } - - - boolean ex = x != ((1< this.maxSize || endX+1 == (1 << this.size) - 1) { + if (ex) { + for (int tz = z; tz < endZ+1; tz++) { + if (!this.canMerge(endX + 1, tz, data)) { ex = false; } } - if (ex) { - for (int tz = z; tz < endZ+1; tz++) { - if (!this.canMerge(endX + 1, tz, data)) { - ex = false; - } - } + } + if (ex) { + endX++; + } + if (ez) { + if (endZ + 1 > this.maxSize || endZ+1 == (1< this.maxSize || endZ+1 == (1<M || z>M) { - throw new IllegalStateException(); - } - return ((z&M)<>24)&0xFF; - } - - public static int getZ(int data) { - return (data>>16)&0xFF; - } - - public static int getH(int data) { - return (data>>8)&0xFF; - } - - public static int getW(int data) { - return data&0xFF; - } - - // - private static int encodeQuad(int x, int z, int sx, int sz) { - return ((x&0xFF)<<24)|((z&0xFF)<<16)|((sx&0xFF)<<8)|((sz&0xFF)<<0); - } - - private boolean canMerge(int x, int z, long match) { - int id = this.getIdx(x, z); - return this.setset.get(id) && this.data[id] == match; - } - - public int[] process() { - int[] quads = this.quadCache; - int idxCount = 0; - - //TODO: add different strategies/ways to mesh - int posId = this.data[0] == 0?this.setset.nextSetBit(0):0; - while (posId < this.data.length && posId != -1) { - int idx = posId; - long data = this.data[idx]; - - int M = (1<>>this.size)&M; - - boolean ex = x != ((1< this.maxSize || endX+1 == (1 << this.size) - 1) { - ex = false; - } - } - if (ex) { - for (int tz = z; tz < endZ+1; tz++) { - if (!this.canMerge(endX + 1, tz, data)) { - ex = false; - } - } - } - if (ex) { - endX++; - } - if (ez) { - if (endZ + 1 > this.maxSize || endZ+1 == (1< { if ((val&1) != 0) { diff --git a/src/main/java/me/cortex/voxelmon/core/world/other/Mapper.java b/src/main/java/me/cortex/voxelmon/core/world/other/Mapper.java index e8c32040..c342cd20 100644 --- a/src/main/java/me/cortex/voxelmon/core/world/other/Mapper.java +++ b/src/main/java/me/cortex/voxelmon/core/world/other/Mapper.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.cortex.voxelmon.core.util.MemoryBuffer; import me.cortex.voxelmon.core.world.storage.StorageBackend; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.nbt.NbtCompound; @@ -51,6 +52,7 @@ public class Mapper { this.loadFromStorage(); } + public static boolean isTranslucent(long id) { //Atm hardcode to air return ((id>>27)&((1<<20)-1)) == 0; @@ -74,8 +76,14 @@ public class Mapper { int id = entry.getIntKey() & ((1<<30)-1); if (entryType == BLOCK_STATE_TYPE) { var sentry = StateEntry.deserialize(id, entry.getValue()); + if (sentry.state.isAir()) { + System.err.println("Deserialization had air, probably corrupt, Inserting garbage type"); + sentry = new StateEntry(id, Block.STATE_IDS.get(new Random().nextInt(Block.STATE_IDS.size()-1))); + //TODO THIS + } sentries.add(sentry); - if (this.block2stateEntry.put(sentry.state, sentry) != null) { + var oldEntry = this.block2stateEntry.put(sentry.state, sentry); + if (oldEntry != null) { throw new IllegalStateException("Multiple mappings for blockstate"); } } else if (entryType == BIOME_TYPE) { diff --git a/src/main/resources/assets/voxelmon/shaders/lod/gl46/quads.vert b/src/main/resources/assets/voxelmon/shaders/lod/gl46/quads.vert index 679f32a4..6630923f 100644 --- a/src/main/resources/assets/voxelmon/shaders/lod/gl46/quads.vert +++ b/src/main/resources/assets/voxelmon/shaders/lod/gl46/quads.vert @@ -85,20 +85,20 @@ void main() { } - //gl_Position = MVP * vec4(vec3(((cornerIdx)&1)+10,10,((cornerIdx>>1)&1)+10),1); - //uint i = uint(quad>>32); - //uint i = uint(gl_BaseInstance); - //i ^= i>>16; - //i *= 124128573; - //i ^= i>>16; - //i *= 4211346123; - //i ^= i>>16; - //i *= 462312435; - //i ^= i>>16; - //i *= 542354341; - //i ^= i>>16; +} +//gl_Position = MVP * vec4(vec3(((cornerIdx)&1)+10,10,((cornerIdx>>1)&1)+10),1); +//uint i = uint(quad>>32); +//uint i = uint(gl_BaseInstance); +//i ^= i>>16; +//i *= 124128573; +//i ^= i>>16; +//i *= 4211346123; +//i ^= i>>16; +//i *= 462312435; +//i ^= i>>16; +//i *= 542354341; +//i ^= i>>16; - //uint i = uint(lodLevel+12)*215387625; - //colour *= vec4(vec3(float((uint(i)>>2)&7)/7,float((uint(i)>>5)&7)/7,float((uint(i)>>8)&7)/7)*0.7+0.3,1); - //colour = vec4(vec3(float((uint(i)>>2)&7)/7,float((uint(i)>>5)&7)/7,float((uint(i)>>8)&7)/7),1); -} \ No newline at end of file +//uint i = uint(lodLevel+12)*215387625; +//colour *= vec4(vec3(float((uint(i)>>2)&7)/7,float((uint(i)>>5)&7)/7,float((uint(i)>>8)&7)/7)*0.7+0.3,1); +//colour = vec4(vec3(float((uint(i)>>2)&7)/7,float((uint(i)>>5)&7)/7,float((uint(i)>>8)&7)/7),1); \ No newline at end of file