mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
Pool party!
- Move index buffer logic into IndexPool class, should let us avoid unnecessary uploads and make it easier to manage
This commit is contained in:
parent
aa46f6ceb1
commit
c4dcebb203
2 changed files with 112 additions and 46 deletions
|
@ -0,0 +1,89 @@
|
||||||
|
package com.jozufozu.flywheel.backend.engine;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.api.model.IndexSequence;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||||
|
|
||||||
|
public class IndexPool {
|
||||||
|
private final GlBuffer ebo;
|
||||||
|
|
||||||
|
private final Reference2IntMap<IndexSequence> indexCounts;
|
||||||
|
private final Reference2IntMap<IndexSequence> firstIndices;
|
||||||
|
|
||||||
|
private boolean dirty;
|
||||||
|
|
||||||
|
public IndexPool() {
|
||||||
|
ebo = new GlBuffer();
|
||||||
|
|
||||||
|
indexCounts = new Reference2IntOpenHashMap<>();
|
||||||
|
firstIndices = new Reference2IntOpenHashMap<>();
|
||||||
|
|
||||||
|
indexCounts.defaultReturnValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int firstIndex(IndexSequence sequence) {
|
||||||
|
return firstIndices.getInt(sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
indexCounts.clear();
|
||||||
|
firstIndices.clear();
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCount(IndexSequence sequence, int indexCount) {
|
||||||
|
int oldCount = indexCounts.getInt(sequence);
|
||||||
|
int newCount = Math.max(oldCount, indexCount);
|
||||||
|
|
||||||
|
if (newCount > oldCount) {
|
||||||
|
indexCounts.put(sequence, newCount);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
if (!dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstIndices.clear();
|
||||||
|
dirty = false;
|
||||||
|
|
||||||
|
long totalIndexCount = 0;
|
||||||
|
|
||||||
|
for (int count : indexCounts.values()) {
|
||||||
|
totalIndexCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var indexBlock = MemoryBlock.malloc(totalIndexCount * GlNumericType.UINT.byteWidth());
|
||||||
|
final long indexPtr = indexBlock.ptr();
|
||||||
|
|
||||||
|
int firstIndex = 0;
|
||||||
|
for (Reference2IntMap.Entry<IndexSequence> entries : indexCounts.reference2IntEntrySet()) {
|
||||||
|
var indexSequence = entries.getKey();
|
||||||
|
var indexCount = entries.getIntValue();
|
||||||
|
|
||||||
|
firstIndices.put(indexSequence, firstIndex);
|
||||||
|
|
||||||
|
indexSequence.fill(indexPtr + (long) firstIndex * GlNumericType.UINT.byteWidth(), indexCount);
|
||||||
|
|
||||||
|
firstIndex += indexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ebo.upload(indexBlock);
|
||||||
|
indexBlock.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(GlVertexArray vertexArray) {
|
||||||
|
vertexArray.setElementBuffer(ebo.handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
ebo.delete();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,27 +9,24 @@ import java.util.Set;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.model.IndexSequence;
|
|
||||||
import com.jozufozu.flywheel.api.model.Mesh;
|
import com.jozufozu.flywheel.api.model.Mesh;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexView;
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
import com.jozufozu.flywheel.backend.InternalVertex;
|
import com.jozufozu.flywheel.backend.InternalVertex;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||||
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceArraySet;
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet;
|
||||||
|
|
||||||
public class MeshPool {
|
public class MeshPool {
|
||||||
private final VertexView vertexView;
|
private final VertexView vertexView;
|
||||||
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
|
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
|
||||||
private final List<BufferedMesh> meshList = new ArrayList<>();
|
private final List<BufferedMesh> meshList = new ArrayList<>();
|
||||||
|
private final List<BufferedMesh> recentlyAllocated = new ArrayList<>();
|
||||||
|
|
||||||
private final GlBuffer vbo;
|
private final GlBuffer vbo;
|
||||||
private final GlBuffer ebo;
|
private final IndexPool indexPool;
|
||||||
|
|
||||||
private boolean dirty;
|
private boolean dirty;
|
||||||
private boolean anyToRemove;
|
private boolean anyToRemove;
|
||||||
|
@ -40,7 +37,7 @@ public class MeshPool {
|
||||||
public MeshPool() {
|
public MeshPool() {
|
||||||
vertexView = InternalVertex.createVertexView();
|
vertexView = InternalVertex.createVertexView();
|
||||||
vbo = new GlBuffer();
|
vbo = new GlBuffer();
|
||||||
ebo = new GlBuffer();
|
indexPool = new IndexPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +53,7 @@ public class MeshPool {
|
||||||
private BufferedMesh _alloc(Mesh m) {
|
private BufferedMesh _alloc(Mesh m) {
|
||||||
BufferedMesh bufferedModel = new BufferedMesh(m);
|
BufferedMesh bufferedModel = new BufferedMesh(m);
|
||||||
meshList.add(bufferedModel);
|
meshList.add(bufferedModel);
|
||||||
|
recentlyAllocated.add(bufferedModel);
|
||||||
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
return bufferedModel;
|
return bufferedModel;
|
||||||
|
@ -74,9 +72,23 @@ public class MeshPool {
|
||||||
if (anyToRemove) {
|
if (anyToRemove) {
|
||||||
anyToRemove = false;
|
anyToRemove = false;
|
||||||
processDeletions();
|
processDeletions();
|
||||||
|
|
||||||
|
// Might want to shrink the index pool if something was removed.
|
||||||
|
indexPool.reset();
|
||||||
|
for (BufferedMesh mesh : meshList) {
|
||||||
|
indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, just update the index with the new counts.
|
||||||
|
for (BufferedMesh mesh : recentlyAllocated) {
|
||||||
|
indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadAll();
|
// Always need to flush the index pool.
|
||||||
|
indexPool.flush();
|
||||||
|
|
||||||
|
uploadAll();
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,41 +105,8 @@ public class MeshPool {
|
||||||
|
|
||||||
private void uploadAll() {
|
private void uploadAll() {
|
||||||
long neededSize = 0;
|
long neededSize = 0;
|
||||||
Reference2IntMap<IndexSequence> indexCounts = new Reference2IntOpenHashMap<>();
|
|
||||||
indexCounts.defaultReturnValue(0);
|
|
||||||
|
|
||||||
for (BufferedMesh mesh : meshList) {
|
for (BufferedMesh mesh : meshList) {
|
||||||
neededSize += mesh.byteSize();
|
neededSize += mesh.byteSize();
|
||||||
|
|
||||||
int count = indexCounts.getInt(mesh.mesh.indexSequence());
|
|
||||||
int newCount = Math.max(count, mesh.indexCount());
|
|
||||||
|
|
||||||
if (newCount > count) {
|
|
||||||
indexCounts.put(mesh.mesh.indexSequence(), newCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long totalIndexCount = 0;
|
|
||||||
|
|
||||||
for (int count : indexCounts.values()) {
|
|
||||||
totalIndexCount += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
final var indexBlock = MemoryBlock.malloc(totalIndexCount * GlNumericType.UINT.byteWidth());
|
|
||||||
final long indexPtr = indexBlock.ptr();
|
|
||||||
|
|
||||||
Reference2IntMap<IndexSequence> firstIndices = new Reference2IntOpenHashMap<>();
|
|
||||||
|
|
||||||
int firstIndex = 0;
|
|
||||||
for (Reference2IntMap.Entry<IndexSequence> entries : indexCounts.reference2IntEntrySet()) {
|
|
||||||
var indexSequence = entries.getKey();
|
|
||||||
var indexCount = entries.getIntValue();
|
|
||||||
|
|
||||||
firstIndices.put(indexSequence, firstIndex);
|
|
||||||
|
|
||||||
indexSequence.fill(indexPtr + (long) firstIndex * GlNumericType.UINT.byteWidth(), indexCount);
|
|
||||||
|
|
||||||
firstIndex += indexCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final var vertexBlock = MemoryBlock.malloc(neededSize);
|
final var vertexBlock = MemoryBlock.malloc(neededSize);
|
||||||
|
@ -144,27 +123,25 @@ public class MeshPool {
|
||||||
byteIndex += mesh.byteSize();
|
byteIndex += mesh.byteSize();
|
||||||
baseVertex += mesh.vertexCount();
|
baseVertex += mesh.vertexCount();
|
||||||
|
|
||||||
mesh.firstIndex = firstIndices.getInt(mesh.mesh.indexSequence());
|
mesh.firstIndex = indexPool.firstIndex(mesh.mesh.indexSequence());
|
||||||
|
|
||||||
mesh.boundTo.clear();
|
mesh.boundTo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
vbo.upload(vertexBlock);
|
vbo.upload(vertexBlock);
|
||||||
ebo.upload(indexBlock);
|
|
||||||
|
|
||||||
vertexBlock.free();
|
vertexBlock.free();
|
||||||
indexBlock.free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(GlVertexArray vertexArray) {
|
public void bind(GlVertexArray vertexArray) {
|
||||||
vertexArray.setElementBuffer(ebo.handle());
|
indexPool.bind(vertexArray);
|
||||||
vertexArray.bindVertexBuffer(0, vbo.handle(), 0, InternalVertex.STRIDE);
|
vertexArray.bindVertexBuffer(0, vbo.handle(), 0, InternalVertex.STRIDE);
|
||||||
vertexArray.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
vertexArray.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
vbo.delete();
|
vbo.delete();
|
||||||
ebo.delete();
|
indexPool.delete();
|
||||||
meshes.clear();
|
meshes.clear();
|
||||||
meshList.clear();
|
meshList.clear();
|
||||||
}
|
}
|
||||||
|
@ -231,7 +208,7 @@ public class MeshPool {
|
||||||
|
|
||||||
public void setup(GlVertexArray vao) {
|
public void setup(GlVertexArray vao) {
|
||||||
if (boundTo.add(vao)) {
|
if (boundTo.add(vao)) {
|
||||||
vao.setElementBuffer(MeshPool.this.ebo.handle());
|
MeshPool.this.indexPool.bind(vao);
|
||||||
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
|
vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE);
|
||||||
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue