diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractArena.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractArena.java index 23d023006..2493a339b 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractArena.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractArena.java @@ -22,7 +22,7 @@ public abstract class AbstractArena { // Make sure there's room to increment top. if (top * elementSizeBytes >= byteCapacity()) { - resize(); + grow(); } // Return the top index and increment. @@ -44,5 +44,5 @@ public abstract class AbstractArena { public abstract long byteCapacity(); - protected abstract void resize(); + protected abstract void grow(); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/CpuArena.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/CpuArena.java index c1c7843d7..33dfa3812 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/CpuArena.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/CpuArena.java @@ -24,7 +24,7 @@ public class CpuArena extends AbstractArena { return memoryBlock.size(); } - protected void resize() { + protected void grow() { memoryBlock = memoryBlock.realloc(memoryBlock.size() * 2); } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java index f82d32c10..1ce962eec 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java @@ -89,9 +89,9 @@ public class IndirectBuffers { MemoryUtil.memPutInt(ptr + MODEL_HANDLE_OFFSET, model.handle()); MemoryUtil.memPutInt(ptr + DRAW_HANDLE_OFFSET, draw.handle()); - MemoryUtil.memPutAddress(ptr + INSTANCE_SIZE_OFFSET, pageFile.storage.byteCapacity()); + MemoryUtil.memPutAddress(ptr + INSTANCE_SIZE_OFFSET, pageFile.storage.capacity()); MemoryUtil.memPutAddress(ptr + TARGET_SIZE_OFFSET, INT_SIZE * instanceCount); - MemoryUtil.memPutAddress(ptr + MODEL_INDEX_SIZE_OFFSET, pageFile.pageTable.byteCapacity()); + MemoryUtil.memPutAddress(ptr + MODEL_INDEX_SIZE_OFFSET, pageFile.pageTable.capacity()); MemoryUtil.memPutAddress(ptr + MODEL_SIZE_OFFSET, MODEL_STRIDE * modelCount); MemoryUtil.memPutAddress(ptr + DRAW_SIZE_OFFSET, DRAW_COMMAND_STRIDE * drawCount); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectInstancer.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectInstancer.java index 541765870..bbd78d88e 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectInstancer.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectInstancer.java @@ -42,14 +42,14 @@ public class IndirectInstancer extends AbstractInstancer return; } changed.set(index); - changedPages.set(pageFile.object2Page(index)); + changedPages.set(InstancePager.object2Page(index)); } @Override protected void setRangeChanged(int start, int end) { super.setRangeChanged(start, end); - changedPages.set(pageFile.object2Page(start), pageFile.object2Page(end)); + changedPages.set(InstancePager.object2Page(start), InstancePager.object2Page(end) + 1); } @Override @@ -88,20 +88,14 @@ public class IndirectInstancer extends AbstractInstancer var instanceCount = instances.size(); - for (int page = 0; page < numPages; page++) { - page = changedPages.nextSetBit(0); - - if (page == -1) { - break; - } - - int startObject = pageFile.page2Object(page); + for (int page = changedPages.nextSetBit(0); page >= 0 && page < numPages; page = changedPages.nextSetBit(page + 1)) { + int startObject = InstancePager.page2Object(page); if (startObject >= instanceCount) { break; } - int endObject = Math.min(instanceCount, pageFile.page2Object(page + 1) - 1); + int endObject = Math.min(instanceCount, InstancePager.page2Object(page + 1)); long baseByte = pageFile.page2ByteOffset(page); long size = (endObject - startObject) * instanceStride; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/InstancePager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/InstancePager.java index 018a640a7..9c746be3d 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/InstancePager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/InstancePager.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.jetbrains.annotations.UnknownNullability; import org.lwjgl.system.MemoryUtil; import dev.engine_room.flywheel.backend.engine.AbstractArena; @@ -12,39 +11,39 @@ import dev.engine_room.flywheel.lib.memory.MemoryBlock; public class InstancePager extends AbstractArena { // 32 objects per page. Allows for convenient bitsets on the gpu. - public static final int DEFAULT_PAGE_SIZE_OBJECTS = 5; - public static final int INITIAL_PAGES_ALLOCATED = 4; + public static final int LOG_2_PAGE_SIZE = 5; + public static final int PAGE_SIZE = 1 << LOG_2_PAGE_SIZE; + public static final int PAGE_MASK = PAGE_SIZE - 1; - private final int log2PageSize; - /** - * The number of objects in a page. - */ - private final int pageSize; + public static final int INITIAL_PAGES_ALLOCATED = 4; private final long objectSizeBytes; - @UnknownNullability private MemoryBlock pageData; - private final int pageMask; - public final ResizableStorageArray storage; - public final ResizableStorageArray pageTable; + public final ResizableStorageBuffer storage; + public final ResizableStorageBuffer pageTable; private final List allocations = new ArrayList<>(); public InstancePager(long objectSizeBytes) { - this(DEFAULT_PAGE_SIZE_OBJECTS, objectSizeBytes); - } - - public InstancePager(int log2PageSize, long objectSizeBytes) { - super((1L << log2PageSize) * objectSizeBytes); - this.log2PageSize = log2PageSize; - this.pageSize = 1 << log2PageSize; - this.pageMask = pageSize - 1; + super(PAGE_SIZE * objectSizeBytes); this.objectSizeBytes = objectSizeBytes; - this.storage = new ResizableStorageArray(this.elementSizeBytes); - this.pageTable = new ResizableStorageArray(Integer.BYTES); + this.storage = new ResizableStorageBuffer(); + this.pageTable = new ResizableStorageBuffer(); + + pageData = MemoryBlock.malloc(INITIAL_PAGES_ALLOCATED * Integer.BYTES); + storage.ensureCapacity(INITIAL_PAGES_ALLOCATED * elementSizeBytes); + pageTable.ensureCapacity(INITIAL_PAGES_ALLOCATED * Integer.BYTES); + } + + public static int object2Page(int objectIndex) { + return objectIndex >> LOG_2_PAGE_SIZE; + } + + public static int page2Object(int pageIndex) { + return pageIndex << LOG_2_PAGE_SIZE; } public Allocation createPage() { @@ -55,20 +54,14 @@ public class InstancePager extends AbstractArena { @Override public long byteCapacity() { - return storage.byteCapacity(); + return storage.capacity(); } @Override - protected void resize() { - if (pageData == null) { - pageData = MemoryBlock.malloc(INITIAL_PAGES_ALLOCATED * Integer.BYTES); - storage.ensureCapacity(INITIAL_PAGES_ALLOCATED); - pageTable.ensureCapacity(INITIAL_PAGES_ALLOCATED); - } else { - pageData = pageData.realloc(pageData.size() * 2); - storage.ensureCapacity(storage.capacity() * 2); - pageTable.ensureCapacity(pageTable.capacity() * 2); - } + protected void grow() { + pageData = pageData.realloc(pageData.size() * 2); + storage.ensureCapacity(storage.capacity() * 2); + pageTable.ensureCapacity(pageTable.capacity() * 2); } public void uploadTable(StagingBuffer stagingBuffer) { @@ -88,6 +81,7 @@ public class InstancePager extends AbstractArena { public int[] pages = new int[0]; private int modelIndex = -1; + private int activeCount = 0; public void modelIndex(int modelIndex) { if (this.modelIndex != modelIndex) { @@ -96,17 +90,28 @@ public class InstancePager extends AbstractArena { } private void updatePageTable() { + if (pages.length == 0) { + return; + } + var ptr = pageData.ptr(); - int fullPage = (modelIndex & 0x3FFFFF) | 0x8000000; + int fullPage = (modelIndex & 0x3FFFFF) | (32 << 26); - for (int page : pages) { + int remainder = activeCount; + + for (int i = 0; i < pages.length - 1; i++) { + int page = pages[i]; MemoryUtil.memPutInt(ptr + page * Integer.BYTES, fullPage); + remainder -= PAGE_SIZE; } + + MemoryUtil.memPutInt(ptr + pages[pages.length - 1] * Integer.BYTES, (modelIndex & 0x3FFFFF) | (remainder << 26)); } public void activeCount(int objectCount) { - var neededPages = object2Page((objectCount + pageMask)); + var neededPages = object2Page((objectCount + PAGE_MASK)); + activeCount = objectCount; var oldLength = pages.length; @@ -126,7 +131,7 @@ public class InstancePager extends AbstractArena { } private void shrink(int oldLength, int neededPages) { - for (int i = oldLength - 1; i > neededPages; i--) { + for (int i = oldLength - 1; i >= neededPages; i--) { var page = pages[i]; InstancePager.this.free(page); MemoryUtil.memPutInt(pageData.ptr() + page * Integer.BYTES, 0); @@ -136,21 +141,13 @@ public class InstancePager extends AbstractArena { } public int capacity() { - return pages.length << log2PageSize; + return pages.length << LOG_2_PAGE_SIZE; } public int pageCount() { return pages.length; } - public int object2Page(int objectIndex) { - return objectIndex >> log2PageSize; - } - - public int page2Object(int pageIndex) { - return pageIndex << log2PageSize; - } - public long page2ByteOffset(int page) { return InstancePager.this.byteOffsetOf(pages[page]); } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl index e45f4ec3d..4186f470d 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl @@ -11,8 +11,8 @@ layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict writeonly buffer T }; // High 6 bits for the number of instances in the page. -const uint _FLW_PAGE_COUNT_OFFSET = 25u; -// Bottom 24 bits for the model index. +const uint _FLW_PAGE_COUNT_OFFSET = 26u; +// Bottom 26 bits for the model index. const uint _FLW_MODEL_INDEX_MASK = 0x3FFFFFF; layout(std430, binding = _FLW_MODEL_INDEX_BUFFER_BINDING) restrict readonly buffer ModelIndexBuffer {