mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-14 22:43:56 +01:00
The hardest problem
- Rename most InstancePager terminology - Rename MODEL_INDEX buffer stuffs
This commit is contained in:
parent
e83a308a46
commit
2537584a22
@ -3,7 +3,7 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
|||||||
public final class BufferBindings {
|
public final class BufferBindings {
|
||||||
public static final int INSTANCE = 0;
|
public static final int INSTANCE = 0;
|
||||||
public static final int TARGET = 1;
|
public static final int TARGET = 1;
|
||||||
public static final int MODEL_INDEX = 2;
|
public static final int PAGE_FRAME_DESCRIPTOR = 2;
|
||||||
public static final int MODEL = 3;
|
public static final int MODEL = 3;
|
||||||
public static final int DRAW = 4;
|
public static final int DRAW = 4;
|
||||||
public static final int LIGHT_LUT = 5;
|
public static final int LIGHT_LUT = 5;
|
||||||
|
@ -32,14 +32,14 @@ public class IndirectBuffers {
|
|||||||
// Offsets to the vbos
|
// Offsets to the vbos
|
||||||
private static final long INSTANCE_HANDLE_OFFSET = HANDLE_OFFSET;
|
private static final long INSTANCE_HANDLE_OFFSET = HANDLE_OFFSET;
|
||||||
private static final long TARGET_HANDLE_OFFSET = INT_SIZE;
|
private static final long TARGET_HANDLE_OFFSET = INT_SIZE;
|
||||||
private static final long MODEL_INDEX_HANDLE_OFFSET = INT_SIZE * 2;
|
private static final long PAGE_FRAME_DESCRIPTOR_HANDLE_OFFSET = INT_SIZE * 2;
|
||||||
private static final long MODEL_HANDLE_OFFSET = INT_SIZE * 3;
|
private static final long MODEL_HANDLE_OFFSET = INT_SIZE * 3;
|
||||||
private static final long DRAW_HANDLE_OFFSET = INT_SIZE * 4;
|
private static final long DRAW_HANDLE_OFFSET = INT_SIZE * 4;
|
||||||
|
|
||||||
// Offsets to the sizes
|
// Offsets to the sizes
|
||||||
private static final long INSTANCE_SIZE_OFFSET = SIZE_OFFSET;
|
private static final long INSTANCE_SIZE_OFFSET = SIZE_OFFSET;
|
||||||
private static final long TARGET_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE;
|
private static final long TARGET_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE;
|
||||||
private static final long MODEL_INDEX_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2;
|
private static final long PAGE_FRAME_DESCRIPTOR_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2;
|
||||||
private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3;
|
private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3;
|
||||||
private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 4;
|
private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 4;
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ public class IndirectBuffers {
|
|||||||
private final MemoryBlock multiBindBlock;
|
private final MemoryBlock multiBindBlock;
|
||||||
private final long instanceStride;
|
private final long instanceStride;
|
||||||
|
|
||||||
public final InstancePager pageFile;
|
public final ObjectStorage objectStorage;
|
||||||
public final ResizableStorageArray target;
|
public final ResizableStorageArray target;
|
||||||
public final ResizableStorageArray model;
|
public final ResizableStorageArray model;
|
||||||
public final ResizableStorageArray draw;
|
public final ResizableStorageArray draw;
|
||||||
@ -71,7 +71,7 @@ public class IndirectBuffers {
|
|||||||
this.instanceStride = instanceStride;
|
this.instanceStride = instanceStride;
|
||||||
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
|
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
|
||||||
|
|
||||||
pageFile = new InstancePager(instanceStride);
|
objectStorage = new ObjectStorage(instanceStride);
|
||||||
target = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
|
target = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
|
||||||
model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
|
model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
|
||||||
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, DRAW_GROWTH_FACTOR);
|
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, DRAW_GROWTH_FACTOR);
|
||||||
@ -83,15 +83,15 @@ public class IndirectBuffers {
|
|||||||
draw.ensureCapacity(drawCount);
|
draw.ensureCapacity(drawCount);
|
||||||
|
|
||||||
final long ptr = multiBindBlock.ptr();
|
final long ptr = multiBindBlock.ptr();
|
||||||
MemoryUtil.memPutInt(ptr + INSTANCE_HANDLE_OFFSET, pageFile.objects.handle());
|
MemoryUtil.memPutInt(ptr + INSTANCE_HANDLE_OFFSET, objectStorage.objectBuffer.handle());
|
||||||
MemoryUtil.memPutInt(ptr + TARGET_HANDLE_OFFSET, target.handle());
|
MemoryUtil.memPutInt(ptr + TARGET_HANDLE_OFFSET, target.handle());
|
||||||
MemoryUtil.memPutInt(ptr + MODEL_INDEX_HANDLE_OFFSET, pageFile.pageTable.handle());
|
MemoryUtil.memPutInt(ptr + PAGE_FRAME_DESCRIPTOR_HANDLE_OFFSET, objectStorage.frameDescriptorBuffer.handle());
|
||||||
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.objects.capacity());
|
MemoryUtil.memPutAddress(ptr + INSTANCE_SIZE_OFFSET, objectStorage.objectBuffer.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.capacity());
|
MemoryUtil.memPutAddress(ptr + PAGE_FRAME_DESCRIPTOR_SIZE_OFFSET, objectStorage.frameDescriptorBuffer.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);
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ public class IndirectBuffers {
|
|||||||
public void delete() {
|
public void delete() {
|
||||||
multiBindBlock.free();
|
multiBindBlock.free();
|
||||||
|
|
||||||
pageFile.delete();
|
objectStorage.delete();
|
||||||
target.delete();
|
target.delete();
|
||||||
model.delete();
|
model.delete();
|
||||||
draw.delete();
|
draw.delete();
|
||||||
|
@ -95,7 +95,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
// Upload only instances that have changed.
|
// Upload only instances that have changed.
|
||||||
uploadInstances(stagingBuffer);
|
uploadInstances(stagingBuffer);
|
||||||
|
|
||||||
buffers.pageFile.uploadTable(stagingBuffer);
|
buffers.objectStorage.uploadDescriptors(stagingBuffer);
|
||||||
|
|
||||||
// We need to upload the models every frame to reset the instance count.
|
// We need to upload the models every frame to reset the instance count.
|
||||||
uploadModels(stagingBuffer);
|
uploadModels(stagingBuffer);
|
||||||
@ -119,7 +119,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
cullProgram.bind();
|
cullProgram.bind();
|
||||||
|
|
||||||
buffers.bindForCompute();
|
buffers.bindForCompute();
|
||||||
glDispatchCompute(buffers.pageFile.capacity(), 1, 1);
|
glDispatchCompute(buffers.objectStorage.capacity(), 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispatchApply() {
|
public void dispatchApply() {
|
||||||
@ -172,7 +172,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(IndirectInstancer<I> instancer, InstancerKey<I> key, MeshPool meshPool) {
|
public void add(IndirectInstancer<I> instancer, InstancerKey<I> key, MeshPool meshPool) {
|
||||||
instancer.pageFile = buffers.pageFile.createAllocation();
|
instancer.mapping = buffers.objectStorage.createMapping();
|
||||||
instancer.postUpdate(instancers.size(), -1);
|
instancer.postUpdate(instancers.size(), -1);
|
||||||
|
|
||||||
instancers.add(instancer);
|
instancers.add(instancer);
|
||||||
@ -245,7 +245,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
|
|
||||||
private void uploadInstances(StagingBuffer stagingBuffer) {
|
private void uploadInstances(StagingBuffer stagingBuffer) {
|
||||||
for (var instancer : instancers) {
|
for (var instancer : instancers) {
|
||||||
instancer.uploadInstances(stagingBuffer, buffers.pageFile.objects.handle());
|
instancer.uploadInstances(stagingBuffer, buffers.objectStorage.objectBuffer.handle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.joml.Vector4fc;
|
import org.joml.Vector4fc;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||||||
|
|
||||||
private final AtomicBitSet changedPages = new AtomicBitSet();
|
private final AtomicBitSet changedPages = new AtomicBitSet();
|
||||||
|
|
||||||
public InstancePager.Allocation pageFile;
|
public ObjectStorage.@UnknownNullability Mapping mapping;
|
||||||
|
|
||||||
private int modelIndex = -1;
|
private int modelIndex = -1;
|
||||||
private int baseInstance = -1;
|
private int baseInstance = -1;
|
||||||
@ -42,14 +43,14 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
changed.set(index);
|
changed.set(index);
|
||||||
changedPages.set(InstancePager.object2Page(index));
|
changedPages.set(ObjectStorage.objectIndex2PageIndex(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(InstancePager.object2Page(start), InstancePager.object2Page(end) + 1);
|
changedPages.set(ObjectStorage.objectIndex2PageIndex(start), ObjectStorage.objectIndex2PageIndex(end) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDraw(IndirectDraw draw) {
|
public void addDraw(IndirectDraw draw) {
|
||||||
@ -67,7 +68,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||||||
public void postUpdate(int modelIndex, int baseInstance) {
|
public void postUpdate(int modelIndex, int baseInstance) {
|
||||||
this.modelIndex = modelIndex;
|
this.modelIndex = modelIndex;
|
||||||
this.baseInstance = baseInstance;
|
this.baseInstance = baseInstance;
|
||||||
pageFile.update(modelIndex, instanceCount());
|
mapping.update(modelIndex, instanceCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeModel(long ptr) {
|
public void writeModel(long ptr) {
|
||||||
@ -81,20 +82,20 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void uploadInstances(StagingBuffer stagingBuffer, int instanceVbo) {
|
public void uploadInstances(StagingBuffer stagingBuffer, int instanceVbo) {
|
||||||
int numPages = pageFile.pageCount();
|
int numPages = mapping.pageCount();
|
||||||
|
|
||||||
var instanceCount = instances.size();
|
var instanceCount = instances.size();
|
||||||
|
|
||||||
for (int page = changedPages.nextSetBit(0); page >= 0 && page < numPages; page = changedPages.nextSetBit(page + 1)) {
|
for (int page = changedPages.nextSetBit(0); page >= 0 && page < numPages; page = changedPages.nextSetBit(page + 1)) {
|
||||||
int startObject = InstancePager.page2Object(page);
|
int startObject = ObjectStorage.pageIndex2ObjectIndex(page);
|
||||||
|
|
||||||
if (startObject >= instanceCount) {
|
if (startObject >= instanceCount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int endObject = Math.min(instanceCount, InstancePager.page2Object(page + 1));
|
int endObject = Math.min(instanceCount, ObjectStorage.pageIndex2ObjectIndex(page + 1));
|
||||||
|
|
||||||
long baseByte = pageFile.page2ByteOffset(page);
|
long baseByte = mapping.page2ByteOffset(page);
|
||||||
long size = (endObject - startObject) * instanceStride;
|
long size = (endObject - startObject) * instanceStride;
|
||||||
|
|
||||||
stagingBuffer.enqueueCopy(size, instanceVbo, baseByte, ptr -> {
|
stagingBuffer.enqueueCopy(size, instanceVbo, baseByte, ptr -> {
|
||||||
@ -115,7 +116,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||||||
draw.delete();
|
draw.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
pageFile.delete();
|
mapping.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int modelIndex() {
|
public int modelIndex() {
|
||||||
|
@ -7,7 +7,7 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
import dev.engine_room.flywheel.backend.engine.AbstractArena;
|
import dev.engine_room.flywheel.backend.engine.AbstractArena;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
|
|
||||||
public class InstancePager extends AbstractArena {
|
public class ObjectStorage 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 LOG_2_PAGE_SIZE = 5;
|
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_SIZE = 1 << LOG_2_PAGE_SIZE;
|
||||||
@ -15,38 +15,39 @@ public class InstancePager extends AbstractArena {
|
|||||||
|
|
||||||
public static final int INITIAL_PAGES_ALLOCATED = 4;
|
public static final int INITIAL_PAGES_ALLOCATED = 4;
|
||||||
|
|
||||||
private MemoryBlock pageTableData;
|
/**
|
||||||
public final ResizableStorageBuffer objects;
|
* The GPU side buffer containing all the objects, logically divided into page frames.
|
||||||
public final ResizableStorageBuffer pageTable;
|
*/
|
||||||
|
public final ResizableStorageBuffer objectBuffer;
|
||||||
|
/**
|
||||||
|
* The GPU side buffer containing 32 bit descriptors for each page frame.
|
||||||
|
*/
|
||||||
|
public final ResizableStorageBuffer frameDescriptorBuffer;
|
||||||
|
/**
|
||||||
|
* The CPU side memory block containing the page descriptors.
|
||||||
|
*/
|
||||||
|
private MemoryBlock frameDescriptors;
|
||||||
|
|
||||||
private boolean needsUpload = false;
|
private boolean needsUpload = false;
|
||||||
|
|
||||||
public InstancePager(long objectSizeBytes) {
|
public ObjectStorage(long objectSizeBytes) {
|
||||||
super(PAGE_SIZE * objectSizeBytes);
|
super(PAGE_SIZE * objectSizeBytes);
|
||||||
|
|
||||||
this.objects = new ResizableStorageBuffer();
|
this.objectBuffer = new ResizableStorageBuffer();
|
||||||
this.pageTable = new ResizableStorageBuffer();
|
this.frameDescriptorBuffer = new ResizableStorageBuffer();
|
||||||
|
|
||||||
pageTableData = MemoryBlock.malloc(INITIAL_PAGES_ALLOCATED * Integer.BYTES);
|
objectBuffer.ensureCapacity(INITIAL_PAGES_ALLOCATED * elementSizeBytes);
|
||||||
objects.ensureCapacity(INITIAL_PAGES_ALLOCATED * elementSizeBytes);
|
frameDescriptorBuffer.ensureCapacity(INITIAL_PAGES_ALLOCATED * Integer.BYTES);
|
||||||
pageTable.ensureCapacity(INITIAL_PAGES_ALLOCATED * Integer.BYTES);
|
frameDescriptors = MemoryBlock.malloc(INITIAL_PAGES_ALLOCATED * Integer.BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int object2Page(int objectIndex) {
|
public Mapping createMapping() {
|
||||||
return objectIndex >> LOG_2_PAGE_SIZE;
|
return new Mapping();
|
||||||
}
|
|
||||||
|
|
||||||
public static int page2Object(int pageIndex) {
|
|
||||||
return pageIndex << LOG_2_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Allocation createAllocation() {
|
|
||||||
return new Allocation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long byteCapacity() {
|
public long byteCapacity() {
|
||||||
return objects.capacity();
|
return objectBuffer.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,56 +58,57 @@ public class InstancePager extends AbstractArena {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void grow() {
|
protected void grow() {
|
||||||
pageTableData = pageTableData.realloc(pageTableData.size() * 2);
|
objectBuffer.ensureCapacity(objectBuffer.capacity() * 2);
|
||||||
objects.ensureCapacity(objects.capacity() * 2);
|
frameDescriptorBuffer.ensureCapacity(frameDescriptorBuffer.capacity() * 2);
|
||||||
pageTable.ensureCapacity(pageTable.capacity() * 2);
|
frameDescriptors = frameDescriptors.realloc(frameDescriptors.size() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uploadTable(StagingBuffer stagingBuffer) {
|
public void uploadDescriptors(StagingBuffer stagingBuffer) {
|
||||||
if (!needsUpload) {
|
if (!needsUpload) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We could be smarter about which spans are uploaded but this thing is so small it's probably not worth it.
|
// We could be smarter about which spans are uploaded but this thing is so small it's probably not worth it.
|
||||||
stagingBuffer.enqueueCopy(pageTableData.ptr(), pageTableData.size(), pageTable.handle(), 0);
|
stagingBuffer.enqueueCopy(frameDescriptors.ptr(), frameDescriptors.size(), frameDescriptorBuffer.handle(), 0);
|
||||||
needsUpload = false;
|
needsUpload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
objects.delete();
|
objectBuffer.delete();
|
||||||
pageTable.delete();
|
frameDescriptorBuffer.delete();
|
||||||
pageTableData.free();
|
frameDescriptors.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ptrForPage(int page) {
|
private long ptrForPage(int page) {
|
||||||
return pageTableData.ptr() + (long) page * Integer.BYTES;
|
return frameDescriptors.ptr() + (long) page * Integer.BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Allocation {
|
public static int objectIndex2PageIndex(int objectIndex) {
|
||||||
public static final int[] EMPTY_ALLOCATION = new int[0];
|
return objectIndex >> LOG_2_PAGE_SIZE;
|
||||||
public int[] pages = EMPTY_ALLOCATION;
|
}
|
||||||
|
|
||||||
|
public static int pageIndex2ObjectIndex(int pageIndex) {
|
||||||
|
return pageIndex << LOG_2_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps serial object indices to pages, and manages the allocation of pages.
|
||||||
|
*/
|
||||||
|
public class Mapping {
|
||||||
|
private static final int[] EMPTY_ALLOCATION = new int[0];
|
||||||
|
private int[] pages = EMPTY_ALLOCATION;
|
||||||
|
|
||||||
private int modelIndex = -1;
|
private int modelIndex = -1;
|
||||||
private int objectCount = 0;
|
private int objectCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the page descriptor for the given page index.
|
* Adjust this allocation to the given model index and object count.
|
||||||
* Runs under the assumption than all pages are full except maybe the last one.
|
*
|
||||||
|
* <p>This method triggers eager resizing of the allocation to fit the new object count.
|
||||||
|
* If the model index is different from the current one, all frame descriptors will be updated.
|
||||||
|
*
|
||||||
|
* @param modelIndex The model index the objects in this allocation are associated with.
|
||||||
|
* @param objectCount The number of objects in this allocation.
|
||||||
*/
|
*/
|
||||||
private int calculatePageDescriptor(int pageIndex) {
|
|
||||||
int countInPage;
|
|
||||||
if (objectCount % PAGE_SIZE != 0 && pageIndex == pages.length - 1) {
|
|
||||||
// Last page && it isn't full -> use the remainder.
|
|
||||||
countInPage = objectCount & PAGE_MASK;
|
|
||||||
} else if (objectCount > 0) {
|
|
||||||
// Full page.
|
|
||||||
countInPage = PAGE_SIZE;
|
|
||||||
} else {
|
|
||||||
// Empty page, this shouldn't be reachable because we eagerly free empty pages.
|
|
||||||
countInPage = 0;
|
|
||||||
}
|
|
||||||
return (modelIndex & 0x3FFFFF) | (countInPage << 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(int modelIndex, int objectCount) {
|
public void update(int modelIndex, int objectCount) {
|
||||||
boolean incremental = this.modelIndex == modelIndex;
|
boolean incremental = this.modelIndex == modelIndex;
|
||||||
|
|
||||||
@ -115,13 +117,13 @@ public class InstancePager extends AbstractArena {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancePager.this.needsUpload = true;
|
ObjectStorage.this.needsUpload = true;
|
||||||
|
|
||||||
this.modelIndex = modelIndex;
|
this.modelIndex = modelIndex;
|
||||||
this.objectCount = objectCount;
|
this.objectCount = objectCount;
|
||||||
|
|
||||||
var oldLength = pages.length;
|
var oldLength = pages.length;
|
||||||
var newLength = object2Page((objectCount + PAGE_MASK));
|
var newLength = objectIndex2PageIndex((objectCount + PAGE_MASK));
|
||||||
|
|
||||||
if (oldLength > newLength) {
|
if (oldLength > newLength) {
|
||||||
// Eagerly free the now unnecessary pages.
|
// Eagerly free the now unnecessary pages.
|
||||||
@ -153,6 +155,42 @@ public class InstancePager extends AbstractArena {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int pageCount() {
|
||||||
|
return pages.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long page2ByteOffset(int page) {
|
||||||
|
return ObjectStorage.this.byteOffsetOf(pages[page]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
for (int page : pages) {
|
||||||
|
ObjectStorage.this.free(page);
|
||||||
|
}
|
||||||
|
pages = EMPTY_ALLOCATION;
|
||||||
|
modelIndex = -1;
|
||||||
|
objectCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the page descriptor for the given page index.
|
||||||
|
* Runs under the assumption than all pages are full except maybe the last one.
|
||||||
|
*/
|
||||||
|
private int calculatePageDescriptor(int pageIndex) {
|
||||||
|
int countInPage;
|
||||||
|
if (objectCount % PAGE_SIZE != 0 && pageIndex == pages.length - 1) {
|
||||||
|
// Last page && it isn't full -> use the remainder.
|
||||||
|
countInPage = objectCount & PAGE_MASK;
|
||||||
|
} else if (objectCount > 0) {
|
||||||
|
// Full page.
|
||||||
|
countInPage = PAGE_SIZE;
|
||||||
|
} else {
|
||||||
|
// Empty page, this shouldn't be reachable because we eagerly free empty pages.
|
||||||
|
countInPage = 0;
|
||||||
|
}
|
||||||
|
return (modelIndex & 0x3FFFFF) | (countInPage << 26);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateRange(int start, int oldLength) {
|
private void updateRange(int start, int oldLength) {
|
||||||
for (int i = start; i < oldLength; i++) {
|
for (int i = start; i < oldLength; i++) {
|
||||||
MemoryUtil.memPutInt(ptrForPage(pages[i]), calculatePageDescriptor(i));
|
MemoryUtil.memPutInt(ptrForPage(pages[i]), calculatePageDescriptor(i));
|
||||||
@ -163,7 +201,7 @@ public class InstancePager extends AbstractArena {
|
|||||||
pages = Arrays.copyOf(pages, neededPages);
|
pages = Arrays.copyOf(pages, neededPages);
|
||||||
|
|
||||||
for (int i = oldLength; i < neededPages; i++) {
|
for (int i = oldLength; i < neededPages; i++) {
|
||||||
var page = InstancePager.this.alloc();
|
var page = ObjectStorage.this.alloc();
|
||||||
pages[i] = page;
|
pages[i] = page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,31 +209,10 @@ 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);
|
ObjectStorage.this.free(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pages = Arrays.copyOf(pages, neededPages);
|
pages = Arrays.copyOf(pages, neededPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int capacity() {
|
|
||||||
return pages.length << LOG_2_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int pageCount() {
|
|
||||||
return pages.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long page2ByteOffset(int page) {
|
|
||||||
return InstancePager.this.byteOffsetOf(pages[page]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete() {
|
|
||||||
for (int page : pages) {
|
|
||||||
InstancePager.this.free(page);
|
|
||||||
}
|
|
||||||
pages = EMPTY_ALLOCATION;
|
|
||||||
modelIndex = -1;
|
|
||||||
objectCount = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
#define _FLW_INSTANCE_BUFFER_BINDING 0
|
#define _FLW_INSTANCE_BUFFER_BINDING 0
|
||||||
#define _FLW_TARGET_BUFFER_BINDING 1
|
#define _FLW_TARGET_BUFFER_BINDING 1
|
||||||
#define _FLW_MODEL_INDEX_BUFFER_BINDING 2
|
#define _FLW_PAGE_FRAME_DESCRIPTOR_BUFFER_BINDING 2
|
||||||
#define _FLW_MODEL_BUFFER_BINDING 3
|
#define _FLW_MODEL_BUFFER_BINDING 3
|
||||||
#define _FLW_DRAW_BUFFER_BINDING 4
|
#define _FLW_DRAW_BUFFER_BINDING 4
|
||||||
#define _FLW_LIGHT_LUT_BUFFER_BINDING 5
|
#define _FLW_LIGHT_LUT_BUFFER_BINDING 5
|
||||||
|
@ -15,8 +15,8 @@ const uint _FLW_PAGE_COUNT_OFFSET = 26u;
|
|||||||
// Bottom 26 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_PAGE_FRAME_DESCRIPTOR_BUFFER_BINDING) restrict readonly buffer PageFrameDescriptorBuffer {
|
||||||
uint _flw_pageTable[];
|
uint _flw_pageFrameDescriptors[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict buffer ModelBuffer {
|
layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict buffer ModelBuffer {
|
||||||
@ -62,11 +62,11 @@ bool _flw_isVisible(uint instanceIndex, uint modelIndex) {
|
|||||||
void main() {
|
void main() {
|
||||||
uint pageIndex = gl_WorkGroupID.x;
|
uint pageIndex = gl_WorkGroupID.x;
|
||||||
|
|
||||||
if (pageIndex >= _flw_pageTable.length()) {
|
if (pageIndex >= _flw_pageFrameDescriptors.length()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint packedModelIndexAndCount = _flw_pageTable[pageIndex];
|
uint packedModelIndexAndCount = _flw_pageFrameDescriptors[pageIndex];
|
||||||
|
|
||||||
uint pageInstanceCount = packedModelIndexAndCount >> _FLW_PAGE_COUNT_OFFSET;
|
uint pageInstanceCount = packedModelIndexAndCount >> _FLW_PAGE_COUNT_OFFSET;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user