Skip to content

Commit

Permalink
cache multi draw batches on regions
Browse files Browse the repository at this point in the history
  • Loading branch information
douira committed Nov 25, 2024
1 parent 87c1bd5 commit d678560
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ public void multiDrawElementsBaseVertex(MultiDrawBatch batch, GlIndexType indexT
batch.pElementCount,
indexType.getFormatId(),
batch.pElementPointer,
batch.size(),
batch.size,
batch.pBaseVertex);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,20 @@ public final class MultiDrawBatch {
public final long pElementCount;
public final long pBaseVertex;

private final int capacity;

public int size;
public boolean isFilled;

public MultiDrawBatch(int capacity) {
this.pElementPointer = MemoryUtil.nmemAlignedAlloc(32, (long) capacity * Pointer.POINTER_SIZE);
MemoryUtil.memSet(this.pElementPointer, 0x0, (long) capacity * Pointer.POINTER_SIZE);

this.pElementCount = MemoryUtil.nmemAlignedAlloc(32, (long) capacity * Integer.BYTES);
this.pBaseVertex = MemoryUtil.nmemAlignedAlloc(32, (long) capacity * Integer.BYTES);

this.capacity = capacity;
}

public int size() {
return this.size;
}

public int capacity() {
return this.capacity;
}

public void clear() {
this.size = 0;
this.isFilled = false;
}

public void delete() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@
import java.util.Iterator;

public class DefaultChunkRenderer extends ShaderChunkRenderer {
private final MultiDrawBatch batch;

private final SharedQuadIndexBuffer sharedIndexBuffer;

public DefaultChunkRenderer(RenderDevice device, ChunkVertexType vertexType) {
super(device, vertexType);

this.batch = new MultiDrawBatch((ModelQuadFacing.COUNT * RenderRegion.REGION_SIZE) + 1);
this.sharedIndexBuffer = new SharedQuadIndexBuffer(device.createCommandList(), SharedQuadIndexBuffer.IndexType.INTEGER);
}

Expand Down Expand Up @@ -72,16 +69,19 @@ public void render(ChunkRenderMatrices matrices,
continue;
}

fillCommandBuffer(this.batch, region, storage, renderList, camera, renderPass, useBlockFaceCulling);
var batch = region.getCachedBatch(renderPass);
if (!batch.isFilled) {
fillCommandBuffer(batch, region, storage, renderList, camera, renderPass, useBlockFaceCulling);
}

if (this.batch.isEmpty()) {
if (batch.isEmpty()) {
continue;
}

// When the shared index buffer is being used, we must ensure the storage has been allocated *before*
// the tessellation is prepared.
if (!useIndexedTessellation) {
this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize());
this.sharedIndexBuffer.ensureCapacity(commandList, batch.getIndexBufferSize());
}

GlTessellation tessellation;
Expand All @@ -93,7 +93,7 @@ public void render(ChunkRenderMatrices matrices,
}

setModelMatrixUniforms(shader, region, camera);
executeDrawBatch(commandList, tessellation, this.batch);
executeDrawBatch(commandList, tessellation, batch);
}

super.end(renderPass);
Expand All @@ -110,7 +110,7 @@ private static void fillCommandBuffer(MultiDrawBatch batch,
CameraTransform camera,
TerrainRenderPass pass,
boolean useBlockFaceCulling) {
batch.clear();
batch.isFilled = true;

var iterator = renderList.sectionsWithGeometryIterator(pass.isTranslucent());

Expand Down Expand Up @@ -321,6 +321,5 @@ public void delete(CommandList commandList) {
super.delete(commandList);

this.sharedIndexBuffer.delete(commandList);
this.batch.delete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class ChunkRenderList {

private final byte[] sectionsWithGeometry = new byte[RenderRegion.REGION_SIZE];
private int sectionsWithGeometryCount = 0;
private int prevSectionsWithGeometryCount = 0;

private final byte[] sectionsWithSprites = new byte[RenderRegion.REGION_SIZE];
private int sectionsWithSpritesCount = 0;
Expand All @@ -32,6 +33,9 @@ public ChunkRenderList(RenderRegion region) {
}

public void reset(int frame) {
// TODO: benchmark overall improvement and test if partial batch writing is worth it
this.prevSectionsWithGeometryCount = this.sectionsWithGeometryCount;

this.sectionsWithGeometryCount = 0;
this.sectionsWithSpritesCount = 0;
this.sectionsWithEntitiesCount = 0;
Expand Down Expand Up @@ -83,8 +87,14 @@ public void add(RenderSection render) {
int index = render.getSectionIndex();
int flags = render.getFlags();

this.sectionsWithGeometry[this.sectionsWithGeometryCount] = (byte) index;
this.sectionsWithGeometryCount += (flags >>> RenderSectionFlags.HAS_BLOCK_GEOMETRY) & 1;
if (((flags >>> RenderSectionFlags.HAS_BLOCK_GEOMETRY) & 1) != 0) {
var byteIndex = (byte) index;
if (this.sectionsWithGeometry[this.sectionsWithGeometryCount] != byteIndex) {
this.sectionsWithGeometry[this.sectionsWithGeometryCount] = byteIndex;
this.prevSectionsWithGeometryCount = -1;
}
this.sectionsWithGeometryCount++;
}

this.sectionsWithSprites[this.sectionsWithSpritesCount] = (byte) index;
this.sectionsWithSpritesCount += (flags >>> RenderSectionFlags.HAS_ANIMATED_SPRITES) & 1;
Expand All @@ -93,6 +103,10 @@ public void add(RenderSection render) {
this.sectionsWithEntitiesCount += (flags >>> RenderSectionFlags.HAS_BLOCK_ENTITIES) & 1;
}

public boolean isCacheInvalidated() {
return this.prevSectionsWithGeometryCount != this.sectionsWithGeometryCount;
}

public @Nullable ByteIterator sectionsWithGeometryIterator(boolean reverse) {
if (this.sectionsWithGeometryCount == 0) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import net.caffeinemc.mods.sodium.client.gl.arena.staging.StagingBuffer;
import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer;
import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
import net.caffeinemc.mods.sodium.client.gl.device.MultiDrawBatch;
import net.caffeinemc.mods.sodium.client.gl.tessellation.GlTessellation;
import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
import net.caffeinemc.mods.sodium.client.render.chunk.data.SectionRenderDataStorage;
import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList;
Expand Down Expand Up @@ -51,6 +53,8 @@ public class RenderRegion {
private final Map<TerrainRenderPass, SectionRenderDataStorage> sectionRenderData = new Reference2ReferenceOpenHashMap<>();
private DeviceResources resources;

private final Map<TerrainRenderPass, MultiDrawBatch> cachedBatches = new Reference2ReferenceOpenHashMap<>();

public RenderRegion(int x, int y, int z, StagingBuffer stagingBuffer) {
this.x = x;
this.y = y;
Expand Down Expand Up @@ -113,6 +117,38 @@ public void delete(CommandList commandList) {
}

Arrays.fill(this.sections, null);

for (var batch : this.cachedBatches.values()) {
batch.delete();
}
this.cachedBatches.clear();
}

public void clearAllCachedBatches() {
for (var batch : this.cachedBatches.values()) {
batch.clear();
}
}

public void clearCachedBatchFor(TerrainRenderPass pass) {
var batch = this.cachedBatches.remove(pass);
if (batch != null) {
batch.delete();
}
}

public MultiDrawBatch getCachedBatch(TerrainRenderPass pass) {
MultiDrawBatch batch = this.cachedBatches.get(pass);
if (batch != null) {
if (this.renderList.isCacheInvalidated()) {
batch.clear();
}
return batch;
}

batch = new MultiDrawBatch((ModelQuadFacing.COUNT * RenderRegion.REGION_SIZE) + 1);
this.cachedBatches.put(pass, batch);
return batch;
}

public boolean isEmpty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect

if (storage != null) {
storage.removeVertexData(renderSectionIndex);
region.clearCachedBatchFor(pass);
}

BuiltSectionMeshParts mesh = chunkBuildOutput.getMesh(pass);
Expand All @@ -100,6 +101,7 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect
var storage = region.getStorage(DefaultTerrainRenderPasses.TRANSLUCENT);
if (storage != null) {
storage.removeIndexData(renderSectionIndex);
region.clearCachedBatchFor(DefaultTerrainRenderPasses.TRANSLUCENT);
}
}
}
Expand All @@ -124,6 +126,7 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect
// Once invalidated the tessellation will be re-created on the next attempted use
if (bufferChanged) {
region.refreshTesselation(commandList);
region.clearAllCachedBatches();
}

// Collect the upload results
Expand All @@ -143,6 +146,7 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect

if (bufferChanged) {
region.refreshIndexedTesselation(commandList);
region.clearCachedBatchFor(DefaultTerrainRenderPasses.TRANSLUCENT);
}

for (PendingSectionIndexBufferUpload upload : indexUploads) {
Expand Down

0 comments on commit d678560

Please sign in to comment.