mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 16:26:07 +01:00
Sparse instance updates
- Use MemoryBlock in IndirectBuffers
This commit is contained in:
parent
3eb15fc84d
commit
2910e33626
6 changed files with 115 additions and 96 deletions
|
@ -5,6 +5,8 @@ import static org.lwjgl.opengl.GL46.*;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import org.lwjgl.system.Pointer;
|
import org.lwjgl.system.Pointer;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
|
||||||
|
|
||||||
public class IndirectBuffers {
|
public class IndirectBuffers {
|
||||||
public static final int BUFFER_COUNT = 4;
|
public static final int BUFFER_COUNT = 4;
|
||||||
public static final long INT_SIZE = Integer.BYTES;
|
public static final long INT_SIZE = Integer.BYTES;
|
||||||
|
@ -30,7 +32,7 @@ public class IndirectBuffers {
|
||||||
private static final long BATCH_SIZE_OFFSET = TARGET_SIZE_OFFSET + PTR_SIZE;
|
private static final long BATCH_SIZE_OFFSET = TARGET_SIZE_OFFSET + PTR_SIZE;
|
||||||
private static final long DRAW_SIZE_OFFSET = BATCH_SIZE_OFFSET + PTR_SIZE;
|
private static final long DRAW_SIZE_OFFSET = BATCH_SIZE_OFFSET + PTR_SIZE;
|
||||||
|
|
||||||
final long buffers;
|
final MemoryBlock buffers;
|
||||||
final long objectStride;
|
final long objectStride;
|
||||||
int object;
|
int object;
|
||||||
int target;
|
int target;
|
||||||
|
@ -46,21 +48,16 @@ public class IndirectBuffers {
|
||||||
|
|
||||||
IndirectBuffers(long objectStride) {
|
IndirectBuffers(long objectStride) {
|
||||||
this.objectStride = objectStride;
|
this.objectStride = objectStride;
|
||||||
this.buffers = MemoryUtil.nmemAlloc(BUFFERS_SIZE_BYTES);
|
this.buffers = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
|
||||||
|
|
||||||
if (this.buffers == MemoryUtil.NULL) {
|
|
||||||
throw new OutOfMemoryError();
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryUtil.memSet(this.buffers, 0, BUFFERS_SIZE_BYTES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createBuffers() {
|
void createBuffers() {
|
||||||
nglCreateBuffers(4, buffers);
|
final long ptr = buffers.ptr();
|
||||||
object = MemoryUtil.memGetInt(buffers);
|
nglCreateBuffers(4, ptr);
|
||||||
target = MemoryUtil.memGetInt(buffers + 4);
|
object = MemoryUtil.memGetInt(ptr);
|
||||||
batch = MemoryUtil.memGetInt(buffers + 8);
|
target = MemoryUtil.memGetInt(ptr + 4);
|
||||||
draw = MemoryUtil.memGetInt(buffers + 12);
|
batch = MemoryUtil.memGetInt(ptr + 8);
|
||||||
|
draw = MemoryUtil.memGetInt(ptr + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateCounts(int objectCount, int drawCount) {
|
void updateCounts(int objectCount, int drawCount) {
|
||||||
|
@ -72,14 +69,15 @@ public class IndirectBuffers {
|
||||||
createDrawStorage(drawCount);
|
createDrawStorage(drawCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
long objectSize = objectStride * objectCount;
|
final long objectSize = objectStride * objectCount;
|
||||||
long targetSize = INT_SIZE * objectCount;
|
final long targetSize = INT_SIZE * objectCount;
|
||||||
long drawSize = DRAW_COMMAND_STRIDE * drawCount;
|
final long drawSize = DRAW_COMMAND_STRIDE * drawCount;
|
||||||
|
|
||||||
MemoryUtil.memPutAddress(buffers + OBJECT_SIZE_OFFSET, objectSize);
|
final long ptr = buffers.ptr();
|
||||||
MemoryUtil.memPutAddress(buffers + TARGET_SIZE_OFFSET, targetSize);
|
MemoryUtil.memPutAddress(ptr + OBJECT_SIZE_OFFSET, objectSize);
|
||||||
MemoryUtil.memPutAddress(buffers + BATCH_SIZE_OFFSET, targetSize);
|
MemoryUtil.memPutAddress(ptr + TARGET_SIZE_OFFSET, targetSize);
|
||||||
MemoryUtil.memPutAddress(buffers + DRAW_SIZE_OFFSET, drawSize);
|
MemoryUtil.memPutAddress(ptr + BATCH_SIZE_OFFSET, targetSize);
|
||||||
|
MemoryUtil.memPutAddress(ptr + DRAW_SIZE_OFFSET, drawSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createObjectStorage(int objectCount) {
|
void createObjectStorage(int objectCount) {
|
||||||
|
@ -112,7 +110,12 @@ public class IndirectBuffers {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindN(int bufferCount) {
|
private void bindN(int bufferCount) {
|
||||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, bufferCount, buffers, buffers + OFFSET_OFFSET, buffers + SIZE_OFFSET);
|
if (bufferCount > BUFFER_COUNT) {
|
||||||
|
throw new IllegalArgumentException("Can't bind more than " + BUFFER_COUNT + " buffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
final long ptr = buffers.ptr();
|
||||||
|
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, bufferCount, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bindIndirectBuffer() {
|
void bindIndirectBuffer() {
|
||||||
|
@ -131,4 +134,9 @@ public class IndirectBuffers {
|
||||||
nglNamedBufferSubData(draw, 0, length, drawPtr);
|
nglNamedBufferSubData(draw, 0, length, drawPtr);
|
||||||
// glFlushMappedNamedBufferRange(this.draw, 0, length);
|
// glFlushMappedNamedBufferRange(this.draw, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
nglDeleteBuffers(BUFFER_COUNT, buffers.ptr());
|
||||||
|
buffers.free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,13 @@ import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.RenderStage;
|
import com.jozufozu.flywheel.api.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
|
||||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
|
||||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
@ -42,7 +37,7 @@ public class IndirectEngine implements Engine {
|
||||||
|
|
||||||
protected final Map<StructType<?>, IndirectFactory<?>> factories = new HashMap<>();
|
protected final Map<StructType<?>, IndirectFactory<?>> factories = new HashMap<>();
|
||||||
|
|
||||||
protected final List<InstancedModel<?>> uninitializedModels = new ArrayList<>();
|
protected final List<IndirectModel<?>> uninitializedModels = new ArrayList<>();
|
||||||
protected final RenderLists renderLists = new RenderLists();
|
protected final RenderLists renderLists = new RenderLists();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,6 +97,8 @@ public class IndirectEngine implements Engine {
|
||||||
factories.values()
|
factories.values()
|
||||||
.forEach(IndirectFactory::delete);
|
.forEach(IndirectFactory::delete);
|
||||||
|
|
||||||
|
renderLists.lists.values().forEach(IndirectList::delete);
|
||||||
|
|
||||||
factories.clear();
|
factories.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,11 @@ import com.jozufozu.flywheel.core.model.Model;
|
||||||
|
|
||||||
public class IndirectFactory<D extends InstancedPart> implements InstancerFactory<D> {
|
public class IndirectFactory<D extends InstancedPart> implements InstancerFactory<D> {
|
||||||
|
|
||||||
protected final Map<Model, InstancedModel<D>> models = new HashMap<>();
|
protected final Map<Model, IndirectModel<D>> models = new HashMap<>();
|
||||||
protected final StructType<D> type;
|
protected final StructType<D> type;
|
||||||
private final Consumer<InstancedModel<D>> creationListener;
|
private final Consumer<IndirectModel<D>> creationListener;
|
||||||
|
|
||||||
public IndirectFactory(StructType<D> type, Consumer<InstancedModel<D>> creationListener) {
|
public IndirectFactory(StructType<D> type, Consumer<IndirectModel<D>> creationListener) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.creationListener = creationListener;
|
this.creationListener = creationListener;
|
||||||
}
|
}
|
||||||
|
@ -27,23 +27,8 @@ public class IndirectFactory<D extends InstancedPart> implements InstancerFactor
|
||||||
return models.computeIfAbsent(modelKey, this::createInstancer).getInstancer();
|
return models.computeIfAbsent(modelKey, this::createInstancer).getInstancer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInstanceCount() {
|
|
||||||
return models.values()
|
|
||||||
.stream()
|
|
||||||
.map(InstancedModel::getInstancer)
|
|
||||||
.mapToInt(AbstractInstancer::getInstanceCount)
|
|
||||||
.sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVertexCount() {
|
|
||||||
return models.values()
|
|
||||||
.stream()
|
|
||||||
.mapToInt(InstancedModel::getVertexCount)
|
|
||||||
.sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
models.values().forEach(InstancedModel::delete);
|
models.values().forEach(IndirectModel::delete);
|
||||||
models.clear();
|
models.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,21 +38,13 @@ public class IndirectFactory<D extends InstancedPart> implements InstancerFactor
|
||||||
public void clear() {
|
public void clear() {
|
||||||
models.values()
|
models.values()
|
||||||
.stream()
|
.stream()
|
||||||
.map(InstancedModel::getInstancer)
|
.map(IndirectModel::getInstancer)
|
||||||
.forEach(AbstractInstancer::clear);
|
.forEach(AbstractInstancer::clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InstancedModel<D> createInstancer(Model model) {
|
private IndirectModel<D> createInstancer(Model model) {
|
||||||
var instancer = new InstancedModel<>(type, model);
|
var instancer = new IndirectModel<>(type, model);
|
||||||
this.creationListener.accept(instancer);
|
this.creationListener.accept(instancer);
|
||||||
return instancer;
|
return instancer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void bindInstanceAttributes(GlVertexArray vao) {
|
|
||||||
// vao.bindAttributes(this.vbo, this.attributeBaseIndex, this.instanceFormat, 0L);
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < this.instanceFormat.getAttributeCount(); i++) {
|
|
||||||
// vao.setAttributeDivisor(this.attributeBaseIndex + i, 1);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
|
||||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||||
|
|
||||||
|
@ -10,12 +9,12 @@ public class IndirectInstancer<D extends InstancedPart> extends AbstractInstance
|
||||||
|
|
||||||
public final BufferLayout instanceFormat;
|
public final BufferLayout instanceFormat;
|
||||||
public final StructType<D> structType;
|
public final StructType<D> structType;
|
||||||
public final InstancedModel<D> parent;
|
public final IndirectModel<D> parent;
|
||||||
int instanceCount = 0;
|
int instanceCount = 0;
|
||||||
|
|
||||||
boolean anyToUpdate;
|
boolean anyToUpdate;
|
||||||
|
|
||||||
public IndirectInstancer(InstancedModel<D> parent, StructType<D> type) {
|
public IndirectInstancer(IndirectModel<D> parent, StructType<D> type) {
|
||||||
super(type);
|
super(type);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.instanceFormat = type.getLayout();
|
this.instanceFormat = type.getLayout();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import static org.lwjgl.opengl.GL46.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.RenderStage;
|
import com.jozufozu.flywheel.api.RenderStage;
|
||||||
|
@ -27,7 +26,6 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
final StorageBufferWriter<T> storageBufferWriter;
|
final StorageBufferWriter<T> storageBufferWriter;
|
||||||
final GlProgram compute;
|
final GlProgram compute;
|
||||||
final GlProgram draw;
|
final GlProgram draw;
|
||||||
private final StructType<T> structType;
|
|
||||||
private final VertexType vertexType;
|
private final VertexType vertexType;
|
||||||
private final long objectStride;
|
private final long objectStride;
|
||||||
|
|
||||||
|
@ -38,12 +36,11 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
|
|
||||||
int vertexArray;
|
int vertexArray;
|
||||||
|
|
||||||
final List<Batch<T>> batches = new ArrayList<>();
|
final List<Batch> batches = new ArrayList<>();
|
||||||
|
|
||||||
IndirectList(StructType<T> structType, VertexType vertexType) {
|
IndirectList(StructType<T> structType, VertexType vertexType) {
|
||||||
this.structType = structType;
|
|
||||||
this.vertexType = vertexType;
|
this.vertexType = vertexType;
|
||||||
storageBufferWriter = this.structType.getStorageBufferWriter();
|
storageBufferWriter = structType.getStorageBufferWriter();
|
||||||
|
|
||||||
objectStride = storageBufferWriter.getAlignment();
|
objectStride = storageBufferWriter.getAlignment();
|
||||||
buffers = new IndirectBuffers(objectStride);
|
buffers = new IndirectBuffers(objectStride);
|
||||||
|
@ -59,7 +56,7 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
.quads2Tris(2048).buffer.handle();
|
.quads2Tris(2048).buffer.handle();
|
||||||
setupVertexArray();
|
setupVertexArray();
|
||||||
|
|
||||||
var indirectShader = this.structType.getIndirectShader();
|
var indirectShader = structType.getIndirectShader();
|
||||||
compute = ComputeCullerCompiler.INSTANCE.get(indirectShader);
|
compute = ComputeCullerCompiler.INSTANCE.get(indirectShader);
|
||||||
draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.CHEST, indirectShader, Components.WORLD, Components.INDIRECT));
|
draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.CHEST, indirectShader, Components.WORLD, Components.INDIRECT));
|
||||||
}
|
}
|
||||||
|
@ -84,14 +81,14 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IndirectInstancer<T> instancer, Material material, Mesh mesh) {
|
public void add(IndirectInstancer<T> instancer, Material material, Mesh mesh) {
|
||||||
batches.add(new Batch<>(instancer, material, meshPool.alloc(mesh)));
|
batches.add(new Batch(instancer, material, meshPool.alloc(mesh)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void submit(RenderStage stage) {
|
void submit(RenderStage stage) {
|
||||||
if (batches.isEmpty()) {
|
if (batches.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int instanceCountThisFrame = calculateTotalInstanceCount();
|
int instanceCountThisFrame = calculateTotalInstanceCountAndPrepareBatches();
|
||||||
|
|
||||||
if (instanceCountThisFrame == 0) {
|
if (instanceCountThisFrame == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -119,7 +116,7 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
|
|
||||||
final int stride = (int) IndirectBuffers.DRAW_COMMAND_STRIDE;
|
final int stride = (int) IndirectBuffers.DRAW_COMMAND_STRIDE;
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
for (Batch<T> batch : batches) {
|
for (var batch : batches) {
|
||||||
|
|
||||||
batch.material.setup();
|
batch.material.setup();
|
||||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset, 1, stride);
|
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, offset, 1, stride);
|
||||||
|
@ -139,22 +136,14 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
private void uploadInstanceData() {
|
private void uploadInstanceData() {
|
||||||
long objectPtr = buffers.objectPtr;
|
long objectPtr = buffers.objectPtr;
|
||||||
long batchIDPtr = buffers.batchPtr;
|
long batchIDPtr = buffers.batchPtr;
|
||||||
int baseInstance = 0;
|
|
||||||
int batchID = 0;
|
|
||||||
for (var batch : batches) {
|
|
||||||
batch.baseInstance = baseInstance;
|
|
||||||
var instancer = batch.instancer;
|
|
||||||
for (T t : instancer.getAll()) {
|
|
||||||
// write object
|
|
||||||
storageBufferWriter.write(objectPtr, t);
|
|
||||||
objectPtr += objectStride;
|
|
||||||
|
|
||||||
// write batchID
|
for (int i = 0, batchesSize = batches.size(); i < batchesSize; i++) {
|
||||||
MemoryUtil.memPutInt(batchIDPtr, batchID);
|
var batch = batches.get(i);
|
||||||
batchIDPtr += IndirectBuffers.INT_SIZE;
|
var instanceCount = batch.instancer.getInstanceCount();
|
||||||
}
|
batch.write(objectPtr, batchIDPtr, i);
|
||||||
baseInstance += batch.instancer.instanceCount;
|
|
||||||
batchID++;
|
objectPtr += instanceCount * objectStride;
|
||||||
|
batchIDPtr += instanceCount * IndirectBuffers.INT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers.flushObjects(objectPtr - buffers.objectPtr);
|
buffers.flushObjects(objectPtr - buffers.objectPtr);
|
||||||
|
@ -163,34 +152,85 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
|
|
||||||
private void uploadIndirectCommands() {
|
private void uploadIndirectCommands() {
|
||||||
long writePtr = buffers.drawPtr;
|
long writePtr = buffers.drawPtr;
|
||||||
for (Batch<T> batch : batches) {
|
for (var batch : batches) {
|
||||||
batch.writeIndirectCommand(writePtr);
|
batch.writeIndirectCommand(writePtr);
|
||||||
writePtr += IndirectBuffers.DRAW_COMMAND_STRIDE;
|
writePtr += IndirectBuffers.DRAW_COMMAND_STRIDE;
|
||||||
}
|
}
|
||||||
buffers.flushDrawCommands(writePtr - buffers.drawPtr);
|
buffers.flushDrawCommands(writePtr - buffers.drawPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int calculateTotalInstanceCount() {
|
private int calculateTotalInstanceCountAndPrepareBatches() {
|
||||||
int total = 0;
|
int baseInstance = 0;
|
||||||
for (Batch<T> batch : batches) {
|
for (var batch : batches) {
|
||||||
batch.instancer.update();
|
batch.prepare(baseInstance);
|
||||||
total += batch.instancer.instanceCount;
|
baseInstance += batch.instancer.instanceCount;
|
||||||
}
|
}
|
||||||
return total;
|
return baseInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Batch<T extends InstancedPart> {
|
public void delete() {
|
||||||
|
glDeleteVertexArrays(vertexArray);
|
||||||
|
buffers.delete();
|
||||||
|
meshPool.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class Batch {
|
||||||
final IndirectInstancer<T> instancer;
|
final IndirectInstancer<T> instancer;
|
||||||
final IndirectMeshPool.BufferedMesh mesh;
|
final IndirectMeshPool.BufferedMesh mesh;
|
||||||
final Material material;
|
final Material material;
|
||||||
int baseInstance = -1;
|
int baseInstance = -1;
|
||||||
|
|
||||||
|
boolean needsFullWrite = true;
|
||||||
|
|
||||||
private Batch(IndirectInstancer<T> instancer, Material material, IndirectMeshPool.BufferedMesh mesh) {
|
private Batch(IndirectInstancer<T> instancer, Material material, IndirectMeshPool.BufferedMesh mesh) {
|
||||||
this.instancer = instancer;
|
this.instancer = instancer;
|
||||||
this.material = material;
|
this.material = material;
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void prepare(int baseInstance) {
|
||||||
|
instancer.update();
|
||||||
|
if (baseInstance == this.baseInstance) {
|
||||||
|
needsFullWrite = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.baseInstance = baseInstance;
|
||||||
|
needsFullWrite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write(long objectPtr, long batchIDPtr, int batchID) {
|
||||||
|
if (needsFullWrite) {
|
||||||
|
writeFull(objectPtr, batchIDPtr, batchID);
|
||||||
|
} else if (instancer.anyToUpdate) {
|
||||||
|
writeSparse(objectPtr, batchIDPtr, batchID);
|
||||||
|
}
|
||||||
|
instancer.anyToUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeSparse(long objectPtr, long batchIDPtr, int batchID) {
|
||||||
|
var all = instancer.getAll();
|
||||||
|
for (int i = 0; i < all.size(); i++) {
|
||||||
|
final var element = all.get(i);
|
||||||
|
if (element.checkDirtyAndClear()) {
|
||||||
|
storageBufferWriter.write(objectPtr + i * objectStride, element);
|
||||||
|
|
||||||
|
MemoryUtil.memPutInt(batchIDPtr + i * IndirectBuffers.INT_SIZE, batchID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFull(long objectPtr, long batchIDPtr, int batchID) {
|
||||||
|
for (var object : this.instancer.getAll()) {
|
||||||
|
// write object
|
||||||
|
storageBufferWriter.write(objectPtr, object);
|
||||||
|
objectPtr += objectStride;
|
||||||
|
|
||||||
|
// write batchID
|
||||||
|
MemoryUtil.memPutInt(batchIDPtr, batchID);
|
||||||
|
batchIDPtr += IndirectBuffers.INT_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void writeIndirectCommand(long ptr) {
|
public void writeIndirectCommand(long ptr) {
|
||||||
var boundingSphere = mesh.mesh.getBoundingSphere();
|
var boundingSphere = mesh.mesh.getBoundingSphere();
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,14 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
|
|
||||||
public class InstancedModel<D extends InstancedPart> {
|
public class IndirectModel<D extends InstancedPart> {
|
||||||
|
|
||||||
private final Model model;
|
private final Model model;
|
||||||
private final StructType<D> type;
|
|
||||||
private final IndirectInstancer<D> instancer;
|
private final IndirectInstancer<D> instancer;
|
||||||
|
|
||||||
public InstancedModel(StructType<D> type, Model model) {
|
public IndirectModel(StructType<D> type, Model model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.instancer = new IndirectInstancer<>(this, type);
|
this.instancer = new IndirectInstancer<>(this, type);
|
||||||
this.type = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(RenderLists renderLists) {
|
public void init(RenderLists renderLists) {
|
Loading…
Reference in a new issue