Skip to content

Commit

Permalink
Improve CPU Cache locality + Class layout optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
thr3343 committed Dec 16, 2023
1 parent 790076a commit 33a6964
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 126 deletions.
23 changes: 7 additions & 16 deletions src/main/java/net/vulkanmod/render/chunk/ChunkArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,17 @@

import net.minecraft.core.BlockPos;
import net.vulkanmod.render.chunk.util.StaticQueue;
import net.vulkanmod.render.vertex.TerrainRenderType;
import org.joml.FrustumIntersection;
import org.joml.Vector3i;

import java.util.Arrays;

public class ChunkArea {
public final int index;
private final byte[] inFrustum = new byte[64];

final Vector3i position;

DrawBuffers drawBuffers;

//Help JIT optimisations by hardcoding the queue size to the max possible ChunkArea limit
final StaticQueue<RenderSection> sectionQueue = new StaticQueue<>(512);
public record ChunkArea(int index, byte[] inFrustum, Vector3i position, DrawBuffers drawBuffers)
{

public ChunkArea(int i, Vector3i origin, int minHeight) {
this.index = i;
this.position = origin;
this.drawBuffers = new DrawBuffers(i, origin, minHeight);
this(i, new byte[64], origin, new DrawBuffers(i, origin, minHeight));
}

public void updateFrustum(VFrustum frustum) {
Expand Down Expand Up @@ -123,12 +114,12 @@ public DrawBuffers getDrawBuffers() {
// this.drawBuffers = new DrawBuffers(this.index, this.position);
// }

public void addSection(RenderSection section) {
this.sectionQueue.add(section);
public void addSection(RenderSection section, TerrainRenderType renderType) {
this.drawBuffers.addDrawCommands(renderType, section.getDrawParameters(renderType));
}

public void resetQueue() {
this.sectionQueue.clear();
this.drawBuffers.clear();
}

public void setPosition(int x, int y, int z) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public void updateFrustumVisibility(VFrustum frustum) {

public void resetQueues() {
for(ChunkArea chunkArea : this.chunkAreasArr) {
chunkArea.sectionQueue.clear();
chunkArea.drawBuffers().clear();
}
}

Expand Down
70 changes: 44 additions & 26 deletions src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,27 @@

import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.EnumMap;
import java.util.Set;

import static org.lwjgl.vulkan.VK10.*;

public class DrawBuffers {

private static final int VERTEX_SIZE = TerrainShaderManager.TERRAIN_VERTEX_FORMAT.getVertexSize();
private static final int INDEX_SIZE = Short.BYTES;
private final int index;
public final int index;
private final Vector3i origin;
private final int minHeight;

private boolean allocated = false;
AreaBuffer vertexBuffer;
AreaBuffer indexBuffer;

//Need ugly minHeight Parameter to fix custom world heights (exceeding 384 Blocks in total)
//Help JIT optimisations by hardcoding the queue size to the max possible ChunkArea limit
// final StaticQueue<DrawParameters> sectionQueue = new StaticQueue<>(512);
private final EnumMap<TerrainRenderType, StaticQueue<DrawParameters>> sectionQueues = new EnumMap<>(TerrainRenderType.class);

public DrawBuffers(int index, Vector3i origin, int minHeight) {

this.index = index;
Expand All @@ -40,6 +45,7 @@ public DrawBuffers(int index, Vector3i origin, int minHeight) {
public void allocateBuffers() {
this.vertexBuffer = new AreaBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 3500000, VERTEX_SIZE);

TerrainRenderType.getActiveLayers().forEach(renderType -> sectionQueues.put(renderType, new StaticQueue<>(512)));
this.allocated = true;
}

Expand Down Expand Up @@ -81,6 +87,11 @@ public DrawParameters upload(int xOffset, int yOffset, int zOffset, UploadBuffer
return drawParameters;
}


private boolean renderTypeEmpty(TerrainRenderType r) {
return this.sectionQueues.get(r).size()==0;
}

private int encodeSectionOffset(int xOffset, int yOffset, int zOffset) {
final int xOffset1 = (xOffset & 127);
final int zOffset1 = (zOffset & 127);
Expand All @@ -96,13 +107,14 @@ private void updateChunkAreaOrigin(double camX, double camY, double camZ, VkComm
nvkCmdPushConstants(commandBuffer, layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 12, ptr);
}

public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, StaticQueue<RenderSection> queue, TerrainRenderType terrainRenderType, double camX, double camY, double camZ, long layout) {
public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, TerrainRenderType terrainRenderType, double camX, double camY, double camZ, long layout) {
int stride = 20;

int drawCount = 0;

if(renderTypeEmpty(terrainRenderType)) return 0;


StaticQueue<DrawParameters> queue = this.sectionQueues.get(terrainRenderType);
MemoryStack stack = MemoryStack.stackPush();
ByteBuffer byteBuffer = stack.calloc(20 * queue.size());
long bufferPtr = MemoryUtil.memAddress0(byteBuffer);
Expand All @@ -117,8 +129,8 @@ public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, StaticQueue<R

var iterator = queue.iterator(isTranslucent);
while (iterator.hasNext()) {
RenderSection section = iterator.next();
DrawParameters drawParameters = section.getDrawParameters(terrainRenderType);
DrawParameters drawParameters = iterator.next();


//Debug
// BlockPos o = section.origin;
Expand Down Expand Up @@ -222,8 +234,8 @@ private static void fakeIndirectCmd(VkCommandBuffer commandBuffer, IndirectBuffe
}


public void buildDrawBatchesDirect(StaticQueue<RenderSection> queue, TerrainRenderType terrainRenderType, double camX, double camY, double camZ, long layout) {

public void buildDrawBatchesDirect(TerrainRenderType terrainRenderType, double camX, double camY, double camZ, long layout) {
if(this.renderTypeEmpty(terrainRenderType)) return;
boolean isTranslucent = terrainRenderType == TerrainRenderType.TRANSLUCENT;

VkCommandBuffer commandBuffer = Renderer.getCommandBuffer();
Expand All @@ -239,13 +251,8 @@ public void buildDrawBatchesDirect(StaticQueue<RenderSection> queue, TerrainRend
vkCmdBindIndexBuffer(commandBuffer, this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16);
}

for (var iterator = queue.iterator(isTranslucent); iterator.hasNext(); ) {
final DrawParameters drawParameters = iterator.next().getDrawParameters(terrainRenderType);

if(drawParameters.indexCount == 0) {
continue;
}

for (var iterator = this.sectionQueues.get(terrainRenderType).iterator(isTranslucent); iterator.hasNext(); ) {
final DrawParameters drawParameters = iterator.next();
vkCmdDrawIndexed(commandBuffer, drawParameters.indexCount, 1, drawParameters.firstIndex, drawParameters.vertexOffset, drawParameters.baseInstance);

}
Expand All @@ -267,19 +274,30 @@ public boolean isAllocated() {
return allocated;
}

public void addDrawCommands(TerrainRenderType r, DrawParameters drawParameters) {
this.sectionQueues.get(r).add(drawParameters);
}

public void clear() {
this.sectionQueues.values().forEach(StaticQueue::clear);
}

public void addRenderTypes(Set<TerrainRenderType> renderTypes) {
renderTypes.forEach(renderType -> this.sectionQueues.computeIfAbsent(renderType, r->new StaticQueue<>(512)));
}

// public void clear(TerrainRenderType r) {
// this.sectionQueues.get(r).clear();
// }

public static class DrawParameters {
int indexCount;
int firstIndex;
int vertexOffset;
int baseInstance;
AreaBuffer.Segment vertexBufferSegment = new AreaBuffer.Segment();
AreaBuffer.Segment indexBufferSegment;
int indexCount, firstIndex, vertexOffset, baseInstance;
final AreaBuffer.Segment vertexBufferSegment = new AreaBuffer.Segment();
final AreaBuffer.Segment indexBufferSegment;
boolean ready = false;

DrawParameters(boolean translucent) {
if(translucent) {
indexBufferSegment = new AreaBuffer.Segment();
}
indexBufferSegment = translucent ? new AreaBuffer.Segment() : null;
}

public void reset(ChunkArea chunkArea) {
Expand All @@ -288,9 +306,9 @@ public void reset(ChunkArea chunkArea) {
this.vertexOffset = 0;

int segmentOffset = this.vertexBufferSegment.getOffset();
if(chunkArea != null && chunkArea.drawBuffers.isAllocated() && segmentOffset != -1) {
if(chunkArea != null && chunkArea.drawBuffers().isAllocated() && segmentOffset != -1) {
// this.chunkArea.drawBuffers.vertexBuffer.setSegmentFree(segmentOffset);
chunkArea.drawBuffers.vertexBuffer.setSegmentFree(this.vertexBufferSegment);
chunkArea.drawBuffers().vertexBuffer.setSegmentFree(this.vertexBufferSegment);
}
}
}
Expand Down
Loading

0 comments on commit 33a6964

Please sign in to comment.