mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-07 10:45:00 +01:00
Growing pains
- Fix bit logic on the GPU - Manually manage the size of the storage and pageTable buffers - Make object2Page and page2Object static - Fix instance writing loop - Fix page table always having full pages - Fix allocations not shrinking
This commit is contained in:
parent
12c7cdfda5
commit
1138208e31
6 changed files with 55 additions and 64 deletions
|
@ -22,7 +22,7 @@ public abstract class AbstractArena {
|
||||||
|
|
||||||
// Make sure there's room to increment top.
|
// Make sure there's room to increment top.
|
||||||
if (top * elementSizeBytes >= byteCapacity()) {
|
if (top * elementSizeBytes >= byteCapacity()) {
|
||||||
resize();
|
grow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the top index and increment.
|
// Return the top index and increment.
|
||||||
|
@ -44,5 +44,5 @@ public abstract class AbstractArena {
|
||||||
|
|
||||||
public abstract long byteCapacity();
|
public abstract long byteCapacity();
|
||||||
|
|
||||||
protected abstract void resize();
|
protected abstract void grow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class CpuArena extends AbstractArena {
|
||||||
return memoryBlock.size();
|
return memoryBlock.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resize() {
|
protected void grow() {
|
||||||
memoryBlock = memoryBlock.realloc(memoryBlock.size() * 2);
|
memoryBlock = memoryBlock.realloc(memoryBlock.size() * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,9 +89,9 @@ public class IndirectBuffers {
|
||||||
MemoryUtil.memPutInt(ptr + MODEL_HANDLE_OFFSET, model.handle());
|
MemoryUtil.memPutInt(ptr + MODEL_HANDLE_OFFSET, model.handle());
|
||||||
MemoryUtil.memPutInt(ptr + DRAW_HANDLE_OFFSET, draw.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 + 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 + MODEL_SIZE_OFFSET, MODEL_STRIDE * modelCount);
|
||||||
MemoryUtil.memPutAddress(ptr + DRAW_SIZE_OFFSET, DRAW_COMMAND_STRIDE * drawCount);
|
MemoryUtil.memPutAddress(ptr + DRAW_SIZE_OFFSET, DRAW_COMMAND_STRIDE * drawCount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,14 +42,14 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
changed.set(index);
|
changed.set(index);
|
||||||
changedPages.set(pageFile.object2Page(index));
|
changedPages.set(InstancePager.object2Page(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setRangeChanged(int start, int end) {
|
protected void setRangeChanged(int start, int end) {
|
||||||
super.setRangeChanged(start, end);
|
super.setRangeChanged(start, end);
|
||||||
|
|
||||||
changedPages.set(pageFile.object2Page(start), pageFile.object2Page(end));
|
changedPages.set(InstancePager.object2Page(start), InstancePager.object2Page(end) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,20 +88,14 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
|
|
||||||
var instanceCount = instances.size();
|
var instanceCount = instances.size();
|
||||||
|
|
||||||
for (int page = 0; page < numPages; page++) {
|
for (int page = changedPages.nextSetBit(0); page >= 0 && page < numPages; page = changedPages.nextSetBit(page + 1)) {
|
||||||
page = changedPages.nextSetBit(0);
|
int startObject = InstancePager.page2Object(page);
|
||||||
|
|
||||||
if (page == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int startObject = pageFile.page2Object(page);
|
|
||||||
|
|
||||||
if (startObject >= instanceCount) {
|
if (startObject >= instanceCount) {
|
||||||
break;
|
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 baseByte = pageFile.page2ByteOffset(page);
|
||||||
long size = (endObject - startObject) * instanceStride;
|
long size = (endObject - startObject) * instanceStride;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.jetbrains.annotations.UnknownNullability;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.engine.AbstractArena;
|
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 {
|
public class InstancePager extends AbstractArena {
|
||||||
// 32 objects per page. Allows for convenient bitsets on the gpu.
|
// 32 objects per page. Allows for convenient bitsets on the gpu.
|
||||||
public static final int DEFAULT_PAGE_SIZE_OBJECTS = 5;
|
public static final int LOG_2_PAGE_SIZE = 5;
|
||||||
public static final int INITIAL_PAGES_ALLOCATED = 4;
|
public static final int PAGE_SIZE = 1 << LOG_2_PAGE_SIZE;
|
||||||
|
public static final int PAGE_MASK = PAGE_SIZE - 1;
|
||||||
|
|
||||||
private final int log2PageSize;
|
public static final int INITIAL_PAGES_ALLOCATED = 4;
|
||||||
/**
|
|
||||||
* The number of objects in a page.
|
|
||||||
*/
|
|
||||||
private final int pageSize;
|
|
||||||
|
|
||||||
private final long objectSizeBytes;
|
private final long objectSizeBytes;
|
||||||
|
|
||||||
@UnknownNullability
|
|
||||||
private MemoryBlock pageData;
|
private MemoryBlock pageData;
|
||||||
|
|
||||||
private final int pageMask;
|
public final ResizableStorageBuffer storage;
|
||||||
public final ResizableStorageArray storage;
|
public final ResizableStorageBuffer pageTable;
|
||||||
public final ResizableStorageArray pageTable;
|
|
||||||
|
|
||||||
private final List<Allocation> allocations = new ArrayList<>();
|
private final List<Allocation> allocations = new ArrayList<>();
|
||||||
|
|
||||||
public InstancePager(long objectSizeBytes) {
|
public InstancePager(long objectSizeBytes) {
|
||||||
this(DEFAULT_PAGE_SIZE_OBJECTS, objectSizeBytes);
|
super(PAGE_SIZE * objectSizeBytes);
|
||||||
}
|
|
||||||
|
|
||||||
public InstancePager(int log2PageSize, long objectSizeBytes) {
|
|
||||||
super((1L << log2PageSize) * objectSizeBytes);
|
|
||||||
this.log2PageSize = log2PageSize;
|
|
||||||
this.pageSize = 1 << log2PageSize;
|
|
||||||
this.pageMask = pageSize - 1;
|
|
||||||
this.objectSizeBytes = objectSizeBytes;
|
this.objectSizeBytes = objectSizeBytes;
|
||||||
|
|
||||||
this.storage = new ResizableStorageArray(this.elementSizeBytes);
|
this.storage = new ResizableStorageBuffer();
|
||||||
this.pageTable = new ResizableStorageArray(Integer.BYTES);
|
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() {
|
public Allocation createPage() {
|
||||||
|
@ -55,20 +54,14 @@ public class InstancePager extends AbstractArena {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long byteCapacity() {
|
public long byteCapacity() {
|
||||||
return storage.byteCapacity();
|
return storage.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void resize() {
|
protected void grow() {
|
||||||
if (pageData == null) {
|
pageData = pageData.realloc(pageData.size() * 2);
|
||||||
pageData = MemoryBlock.malloc(INITIAL_PAGES_ALLOCATED * Integer.BYTES);
|
storage.ensureCapacity(storage.capacity() * 2);
|
||||||
storage.ensureCapacity(INITIAL_PAGES_ALLOCATED);
|
pageTable.ensureCapacity(pageTable.capacity() * 2);
|
||||||
pageTable.ensureCapacity(INITIAL_PAGES_ALLOCATED);
|
|
||||||
} else {
|
|
||||||
pageData = pageData.realloc(pageData.size() * 2);
|
|
||||||
storage.ensureCapacity(storage.capacity() * 2);
|
|
||||||
pageTable.ensureCapacity(pageTable.capacity() * 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uploadTable(StagingBuffer stagingBuffer) {
|
public void uploadTable(StagingBuffer stagingBuffer) {
|
||||||
|
@ -88,6 +81,7 @@ public class InstancePager extends AbstractArena {
|
||||||
public int[] pages = new int[0];
|
public int[] pages = new int[0];
|
||||||
|
|
||||||
private int modelIndex = -1;
|
private int modelIndex = -1;
|
||||||
|
private int activeCount = 0;
|
||||||
|
|
||||||
public void modelIndex(int modelIndex) {
|
public void modelIndex(int modelIndex) {
|
||||||
if (this.modelIndex != modelIndex) {
|
if (this.modelIndex != modelIndex) {
|
||||||
|
@ -96,17 +90,28 @@ public class InstancePager extends AbstractArena {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePageTable() {
|
private void updatePageTable() {
|
||||||
|
if (pages.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var ptr = pageData.ptr();
|
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);
|
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) {
|
public void activeCount(int objectCount) {
|
||||||
var neededPages = object2Page((objectCount + pageMask));
|
var neededPages = object2Page((objectCount + PAGE_MASK));
|
||||||
|
activeCount = objectCount;
|
||||||
|
|
||||||
var oldLength = pages.length;
|
var oldLength = pages.length;
|
||||||
|
|
||||||
|
@ -126,7 +131,7 @@ public class InstancePager extends AbstractArena {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shrink(int oldLength, int neededPages) {
|
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];
|
var page = pages[i];
|
||||||
InstancePager.this.free(page);
|
InstancePager.this.free(page);
|
||||||
MemoryUtil.memPutInt(pageData.ptr() + page * Integer.BYTES, 0);
|
MemoryUtil.memPutInt(pageData.ptr() + page * Integer.BYTES, 0);
|
||||||
|
@ -136,21 +141,13 @@ public class InstancePager extends AbstractArena {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int capacity() {
|
public int capacity() {
|
||||||
return pages.length << log2PageSize;
|
return pages.length << LOG_2_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int pageCount() {
|
public int pageCount() {
|
||||||
return pages.length;
|
return pages.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int object2Page(int objectIndex) {
|
|
||||||
return objectIndex >> log2PageSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int page2Object(int pageIndex) {
|
|
||||||
return pageIndex << log2PageSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long page2ByteOffset(int page) {
|
public long page2ByteOffset(int page) {
|
||||||
return InstancePager.this.byteOffsetOf(pages[page]);
|
return InstancePager.this.byteOffsetOf(pages[page]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
// High 6 bits for the number of instances in the page.
|
||||||
const uint _FLW_PAGE_COUNT_OFFSET = 25u;
|
const uint _FLW_PAGE_COUNT_OFFSET = 26u;
|
||||||
// Bottom 24 bits for the model index.
|
// Bottom 26 bits for the model index.
|
||||||
const uint _FLW_MODEL_INDEX_MASK = 0x3FFFFFF;
|
const uint _FLW_MODEL_INDEX_MASK = 0x3FFFFFF;
|
||||||
|
|
||||||
layout(std430, binding = _FLW_MODEL_INDEX_BUFFER_BINDING) restrict readonly buffer ModelIndexBuffer {
|
layout(std430, binding = _FLW_MODEL_INDEX_BUFFER_BINDING) restrict readonly buffer ModelIndexBuffer {
|
||||||
|
|
Loading…
Reference in a new issue