diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java index 795ece566..e4dc0ce91 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java @@ -40,11 +40,6 @@ public abstract class AbstractInstancer implements Instancer return instances.size(); } - protected boolean moreThanTwoThirdsChanged() { - return (changed.cardinality() * 3) > (instances.size() * 2); - } - - public void notifyDirty(int index) { if (index < 0 || index >= getInstanceCount()) { return; @@ -68,21 +63,34 @@ public abstract class AbstractInstancer implements Instancer final int oldSize = this.instances.size(); int removeCount = deleted.cardinality(); + if (oldSize == removeCount) { + clear(); + return; + } + final int newSize = oldSize - removeCount; - // shift surviving elements left over the spaces left by removed elements - for (int i = 0, j = 0; (i < oldSize) && (j < newSize); i++, j++) { - i = deleted.nextClearBit(i); + // Punch out the deleted instances, shifting over surviving instances to fill their place. + for (int scanPos = 0, writePos = 0; (scanPos < oldSize) && (writePos < newSize); scanPos++, writePos++) { + // Find next non-deleted element. + scanPos = deleted.nextClearBit(scanPos); - if (i != j) { - var handle = handles.get(i); - I instance = instances.get(i); + if (scanPos != writePos) { + // Grab the old instance/handle from scanPos... + var handle = handles.get(scanPos); + I instance = instances.get(scanPos); - handles.set(j, handle); - instances.set(j, instance); + // ... and move it to writePos. + handles.set(writePos, handle); + instances.set(writePos, instance); - handle.index = j; - changed.set(j); + // Make sure the handle knows it's been moved... + handle.index = writePos; + // ...and set it changed to force an upload. + changed.set(writePos); + + // Clear the old slot. There's nothing meaningful there that can be considered "changed". + changed.clear(scanPos); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java index be214c39a..820ef2c4a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java @@ -19,6 +19,8 @@ public class InstanceHandleImpl implements InstanceHandle { @Override public void setDeleted() { instancer.notifyRemoval(index); + // invalidate ourselves + clear(); } public void clear() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java index 0cbb4d989..f855836d6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java @@ -76,26 +76,9 @@ public class IndirectEngine extends AbstractEngine { executor.syncUntil(flushFlag::isRaised); try (var restoreState = GlStateTracker.getRestoreState()) { - int prevActiveTexture = GlStateManager._getActiveTexture(); - Minecraft.getInstance().gameRenderer.overlayTexture() - .setupOverlayColor(); - Minecraft.getInstance().gameRenderer.lightTexture() - .turnOnLightLayer(); - - GlTextureUnit.T1.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(1)); - GlTextureUnit.T2.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(2)); - drawManager.renderCrumbling(crumblingBlocks); MaterialRenderState.reset(); - - Minecraft.getInstance().gameRenderer.overlayTexture() - .teardownOverlayColor(); - Minecraft.getInstance().gameRenderer.lightTexture() - .turnOffLightLayer(); - GlStateManager._activeTexture(prevActiveTexture); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/AtomicBitset.java b/src/main/java/com/jozufozu/flywheel/lib/util/AtomicBitset.java index 472f9b5dc..9d1a30b89 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/AtomicBitset.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/AtomicBitset.java @@ -168,13 +168,13 @@ public class AtomicBitset { if (++longPosition > segmentMask) { segmentPosition++; if (segmentPosition >= segments.numSegments()) { - return segments.numSegments() << log2SegmentSize; + return segments.numSegments() << log2SegmentSize + (longPosition << 6); } segment = segments.getSegment(segmentPosition); longPosition = 0; } - word = segment.get(longPosition); + word = ~segment.get(longPosition); } } diff --git a/src/test/java/com/jozufozu/flywheel/lib/util/TestAtomicBitset.java b/src/test/java/com/jozufozu/flywheel/lib/util/TestAtomicBitset.java new file mode 100644 index 000000000..43b384da3 --- /dev/null +++ b/src/test/java/com/jozufozu/flywheel/lib/util/TestAtomicBitset.java @@ -0,0 +1,40 @@ +package com.jozufozu.flywheel.lib.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestAtomicBitset { + + @Test + void testNextClearBit() { + var segmentLength = 1 << AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS; + var bitLength = 2 << AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS; + var bs = new AtomicBitset(AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS, bitLength); + + Assertions.assertEquals(0, bs.nextClearBit(0)); + Assertions.assertEquals(1, bs.nextClearBit(1)); + + Assertions.assertEquals(5000, bs.nextClearBit(5000)); + + bs.set(16); + + Assertions.assertEquals(0, bs.nextClearBit(0)); + Assertions.assertEquals(17, bs.nextClearBit(16)); + + bs.set(segmentLength + 1); + + Assertions.assertEquals(0, bs.nextClearBit(0)); + Assertions.assertEquals(segmentLength + 2, bs.nextClearBit(segmentLength + 1)); + + bs.set(bitLength); + + Assertions.assertEquals(0, bs.nextClearBit(0)); + Assertions.assertEquals(bitLength + 1, bs.nextClearBit(bitLength)); + + for (int i = 0; i < bitLength; i++) { + bs.set(i); + } + + Assertions.assertEquals(bitLength + 1, bs.nextClearBit(0)); + } +}