mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-27 20:24:39 +01:00
BatchingTransformManager
- Rename BatchingDrawManager to BatchingTransformManager - Rename BatchDrawingTracker to BatchingDrawTracker - Move BatchDrawingTracker from BatchingTransformManager to BatchingEngine - Do not prepare DrawBuffer if number of vertices is 0 - Add DrawBuffer#isPrepared - Add checks to DrawBuffer methods - Remove commented code from CPUInstancerFactory
This commit is contained in:
parent
a29ba6e24a
commit
5d5cd19928
6 changed files with 78 additions and 66 deletions
|
@ -9,12 +9,12 @@ import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
public class BatchDrawingTracker {
|
public class BatchingDrawTracker {
|
||||||
|
|
||||||
protected final Set<RenderType> activeTypes = new HashSet<>();
|
private final Set<RenderType> activeTypes = new HashSet<>();
|
||||||
private final BufferBuilder scratch;
|
private final BufferBuilder scratch;
|
||||||
|
|
||||||
public BatchDrawingTracker() {
|
public BatchingDrawTracker() {
|
||||||
scratch = new BufferBuilder(8);
|
scratch = new BufferBuilder(8);
|
||||||
|
|
||||||
((BufferBuilderExtension) scratch).flywheel$freeBuffer();
|
((BufferBuilderExtension) scratch).flywheel$freeBuffer();
|
||||||
|
@ -25,13 +25,20 @@ public class BatchDrawingTracker {
|
||||||
return RenderTypeExtension.getDrawBuffer(renderType);
|
return RenderTypeExtension.getDrawBuffer(renderType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw and reset the DrawBuffer for the given RenderType.
|
||||||
|
* @param renderType The RenderType to draw.
|
||||||
|
*/
|
||||||
|
public void draw(RenderType renderType) {
|
||||||
|
_draw(renderType);
|
||||||
|
|
||||||
|
activeTypes.remove(renderType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws all active DrawBuffers and reset them.
|
* Draws all active DrawBuffers and reset them.
|
||||||
*/
|
*/
|
||||||
public void endBatch() {
|
public void drawAll() {
|
||||||
// TODO: when/if this causes trouble with shaders, try to inject our BufferBuilders
|
|
||||||
// into the RenderBuffers from context.
|
|
||||||
|
|
||||||
for (RenderType renderType : activeTypes) {
|
for (RenderType renderType : activeTypes) {
|
||||||
_draw(renderType);
|
_draw(renderType);
|
||||||
}
|
}
|
||||||
|
@ -39,38 +46,27 @@ public class BatchDrawingTracker {
|
||||||
activeTypes.clear();
|
activeTypes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void _draw(RenderType renderType) {
|
||||||
* Draw and reset the DrawBuffer for the given RenderType.
|
DrawBuffer buffer = RenderTypeExtension.getDrawBuffer(renderType);
|
||||||
* @param renderType The RenderType to draw.
|
|
||||||
*/
|
|
||||||
public void endBatch(RenderType renderType) {
|
|
||||||
_draw(renderType);
|
|
||||||
|
|
||||||
activeTypes.remove(renderType);
|
if (buffer.hasVertices()) {
|
||||||
|
BufferBuilderExtension scratch = (BufferBuilderExtension) this.scratch;
|
||||||
|
buffer.inject(scratch);
|
||||||
|
renderType.end(this.scratch, 0, 0, 0);
|
||||||
|
buffer.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets all DrawBuffers to 0 vertices.
|
* Resets all DrawBuffers to 0 vertices.
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void reset() {
|
||||||
for (RenderType type : activeTypes) {
|
for (RenderType type : activeTypes) {
|
||||||
RenderTypeExtension.getDrawBuffer(type)
|
RenderTypeExtension.getDrawBuffer(type)
|
||||||
.reset();
|
.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
activeTypes.clear();
|
activeTypes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _draw(RenderType renderType) {
|
|
||||||
DrawBuffer drawBuffer = RenderTypeExtension.getDrawBuffer(renderType);
|
|
||||||
|
|
||||||
BufferBuilderExtension scratch = (BufferBuilderExtension) this.scratch;
|
|
||||||
if (drawBuffer.hasVertices()) {
|
|
||||||
drawBuffer.inject(scratch);
|
|
||||||
|
|
||||||
renderType.end(this.scratch, 0, 0, 0);
|
|
||||||
|
|
||||||
drawBuffer.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -24,7 +24,8 @@ import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class BatchingEngine implements Engine {
|
public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
protected final BatchingDrawManager drawManager = new BatchingDrawManager();
|
protected final BatchingTransformManager transformManager = new BatchingTransformManager();
|
||||||
|
protected final BatchingDrawTracker drawTracker = new BatchingDrawTracker();
|
||||||
protected final Map<StructType<?>, CPUInstancerFactory<?>> factories = new HashMap<>();
|
protected final Map<StructType<?>, CPUInstancerFactory<?>> factories = new HashMap<>();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -36,12 +37,12 @@ public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private <D extends InstancedPart> CPUInstancerFactory<D> createFactory(StructType<D> type) {
|
private <D extends InstancedPart> CPUInstancerFactory<D> createFactory(StructType<D> type) {
|
||||||
return new CPUInstancerFactory<>(type, drawManager::create);
|
return new CPUInstancerFactory<>(type, transformManager::create);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||||
drawManager.flush();
|
transformManager.flush();
|
||||||
|
|
||||||
Vec3 cameraPos = context.camera().getPosition();
|
Vec3 cameraPos = context.camera().getPosition();
|
||||||
var stack = FlwUtil.copyPoseStack(context.stack());
|
var stack = FlwUtil.copyPoseStack(context.stack());
|
||||||
|
@ -51,25 +52,29 @@ public class BatchingEngine implements Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submitTasks(TaskEngine taskEngine, PoseStack stack, ClientLevel level) {
|
public void submitTasks(TaskEngine taskEngine, PoseStack stack, ClientLevel level) {
|
||||||
BatchingDrawManager.TransformSet drawSet = drawManager.get(RenderStage.AFTER_FINAL_END_BATCH);
|
BatchingTransformManager.TransformSet transformSet = transformManager.get(RenderStage.AFTER_FINAL_END_BATCH);
|
||||||
for (var entry : drawSet) {
|
for (var entry : transformSet) {
|
||||||
var renderType = entry.getKey();
|
var renderType = entry.getKey();
|
||||||
var renderList = entry.getValue();
|
var transformCalls = entry.getValue();
|
||||||
|
|
||||||
int vertices = 0;
|
int vertices = 0;
|
||||||
for (var transformSet : renderList) {
|
for (var transformCall : transformCalls) {
|
||||||
vertices += transformSet.getTotalVertexCount();
|
vertices += transformCall.getTotalVertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawBuffer buffer = drawManager.batchTracker.getBuffer(renderType);
|
if (vertices == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawBuffer buffer = drawTracker.getBuffer(renderType);
|
||||||
buffer.prepare(vertices);
|
buffer.prepare(vertices);
|
||||||
|
|
||||||
int startVertex = 0;
|
int startVertex = 0;
|
||||||
for (var transformSet : renderList) {
|
for (var transformCall : transformCalls) {
|
||||||
transformSet.submitTasks(taskEngine, buffer, startVertex, stack, level);
|
transformCall.submitTasks(taskEngine, buffer, startVertex, stack, level);
|
||||||
startVertex += transformSet.getTotalVertexCount();
|
startVertex += transformCall.getTotalVertexCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,7 +86,7 @@ public class BatchingEngine implements Engine {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawManager.batchTracker.endBatch();
|
drawTracker.drawAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,7 +108,7 @@ public class BatchingEngine implements Engine {
|
||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
factories.clear();
|
factories.clear();
|
||||||
drawManager.delete();
|
transformManager.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -17,15 +18,19 @@ import com.jozufozu.flywheel.core.model.Model;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
public class BatchingDrawManager {
|
public class BatchingTransformManager {
|
||||||
|
|
||||||
private final List<UninitializedModel> uninitializedModels = new ArrayList<>();
|
private final List<UninitializedModel> uninitializedModels = new ArrayList<>();
|
||||||
private final List<CPUInstancer<?>> allInstancers = new ArrayList<>();
|
private final List<CPUInstancer<?>> allInstancers = new ArrayList<>();
|
||||||
public final Map<RenderStage, TransformSet> renderLists = new EnumMap<>(RenderStage.class);
|
private final Map<RenderStage, TransformSet> transformSets = new EnumMap<>(RenderStage.class);
|
||||||
public final BatchDrawingTracker batchTracker = new BatchDrawingTracker();
|
private final Map<RenderStage, TransformSet> transformSetsView = Collections.unmodifiableMap(transformSets);
|
||||||
|
|
||||||
public TransformSet get(RenderStage stage) {
|
public TransformSet get(RenderStage stage) {
|
||||||
return renderLists.getOrDefault(stage, TransformSet.EMPTY);
|
return transformSets.getOrDefault(stage, TransformSet.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<RenderStage, TransformSet> getTransformSetsView() {
|
||||||
|
return transformSetsView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void create(CPUInstancer<?> instancer, Model model) {
|
public void create(CPUInstancer<?> instancer, Model model) {
|
||||||
|
@ -55,8 +60,8 @@ public class BatchingDrawManager {
|
||||||
var material = transformCall.getMaterial();
|
var material = transformCall.getMaterial();
|
||||||
var renderType = material.getBatchingRenderType();
|
var renderType = material.getBatchingRenderType();
|
||||||
|
|
||||||
// renderLists.computeIfAbsent(material.getRenderStage(), TransformSet::new)
|
// transformSets.computeIfAbsent(material.getRenderStage(), TransformSet::new)
|
||||||
renderLists.computeIfAbsent(RenderStage.AFTER_FINAL_END_BATCH, TransformSet::new)
|
transformSets.computeIfAbsent(RenderStage.AFTER_FINAL_END_BATCH, TransformSet::new)
|
||||||
.put(renderType, transformCall);
|
.put(renderType, transformCall);
|
||||||
}
|
}
|
||||||
allInstancers.add(instancer);
|
allInstancers.add(instancer);
|
|
@ -26,14 +26,6 @@ public class CPUInstancerFactory<D extends InstancedPart> implements InstancerFa
|
||||||
return models.computeIfAbsent(modelKey, this::createInstancer);
|
return models.computeIfAbsent(modelKey, this::createInstancer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Clear all instance data without freeing resources.
|
|
||||||
// */
|
|
||||||
// public void clear() {
|
|
||||||
// models.values()
|
|
||||||
// .forEach(BatchedModel::clear);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private CPUInstancer<D> createInstancer(Model model) {
|
private CPUInstancer<D> createInstancer(Model model) {
|
||||||
var instancer = new CPUInstancer<>(type);
|
var instancer = new CPUInstancer<>(type);
|
||||||
creationListener.accept(instancer, model);
|
creationListener.accept(instancer, model);
|
||||||
|
|
|
@ -28,7 +28,8 @@ public class DrawBuffer {
|
||||||
private MemoryBlock memory;
|
private MemoryBlock memory;
|
||||||
private ByteBuffer buffer;
|
private ByteBuffer buffer;
|
||||||
|
|
||||||
private int expectedVertices;
|
private boolean prepared;
|
||||||
|
private int vertexCount;
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public DrawBuffer(VertexFormat format) {
|
public DrawBuffer(VertexFormat format) {
|
||||||
|
@ -45,11 +46,11 @@ public class DrawBuffer {
|
||||||
* @throws IllegalStateException If the buffer is already in use.
|
* @throws IllegalStateException If the buffer is already in use.
|
||||||
*/
|
*/
|
||||||
public void prepare(int vertexCount) {
|
public void prepare(int vertexCount) {
|
||||||
if (expectedVertices != 0) {
|
if (prepared) {
|
||||||
throw new IllegalStateException("Already drawing!");
|
throw new IllegalStateException("Cannot prepare DrawBuffer twice!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.expectedVertices = vertexCount;
|
this.vertexCount = vertexCount;
|
||||||
|
|
||||||
// Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least
|
// Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least
|
||||||
// enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer
|
// enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer
|
||||||
|
@ -65,9 +66,14 @@ public class DrawBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.clear();
|
memory.clear();
|
||||||
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
||||||
|
if (!prepared) {
|
||||||
|
throw new IllegalStateException("Cannot slice DrawBuffer that is not prepared!");
|
||||||
|
}
|
||||||
|
|
||||||
ReusableVertexList vertexList = provider.createVertexList();
|
ReusableVertexList vertexList = provider.createVertexList();
|
||||||
vertexList.ptr(memory.ptr());
|
vertexList.ptr(memory.ptr());
|
||||||
vertexList.shiftPtr(startVertex);
|
vertexList.shiftPtr(startVertex);
|
||||||
|
@ -80,19 +86,27 @@ public class DrawBuffer {
|
||||||
* @param bufferBuilder The buffer builder to inject into.
|
* @param bufferBuilder The buffer builder to inject into.
|
||||||
*/
|
*/
|
||||||
public void inject(BufferBuilderExtension bufferBuilder) {
|
public void inject(BufferBuilderExtension bufferBuilder) {
|
||||||
|
if (!prepared) {
|
||||||
|
throw new IllegalStateException("Cannot inject DrawBuffer that is not prepared!");
|
||||||
|
}
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
bufferBuilder.flywheel$injectForRender(buffer, format, expectedVertices);
|
bufferBuilder.flywheel$injectForRender(buffer, format, vertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrepared() {
|
||||||
|
return prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVertexCount() {
|
public int getVertexCount() {
|
||||||
return expectedVertices;
|
return vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@code true} if the buffer has any vertices.
|
* @return {@code true} if the buffer has any vertices.
|
||||||
*/
|
*/
|
||||||
public boolean hasVertices() {
|
public boolean hasVertices() {
|
||||||
return expectedVertices > 0;
|
return vertexCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,7 +115,8 @@ public class DrawBuffer {
|
||||||
* Does not clear the backing buffer.
|
* Does not clear the backing buffer.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
this.expectedVertices = 0;
|
prepared = false;
|
||||||
|
vertexCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void free() {
|
public void free() {
|
||||||
|
|
|
@ -25,7 +25,6 @@ public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
||||||
|
|
||||||
boolean anyToUpdate;
|
boolean anyToUpdate;
|
||||||
|
|
||||||
|
|
||||||
public GPUInstancer(StructType<D> type) {
|
public GPUInstancer(StructType<D> type) {
|
||||||
super(type);
|
super(type);
|
||||||
this.instanceFormat = type.getLayout();
|
this.instanceFormat = type.getLayout();
|
||||||
|
|
Loading…
Add table
Reference in a new issue