Skip to content

Commit 374ddfc

Browse files
committed
Improve terrain rendering command recording
- aggregate draw cmds
1 parent 9417f91 commit 374ddfc

4 files changed

Lines changed: 181 additions & 44 deletions

File tree

src/main/java/net/vulkanmod/render/chunk/buffer/AreaBuffer.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,60 @@ private Buffer allocateBuffer() {
5252
return buffer;
5353
}
5454

55-
public Segment upload(ByteBuffer byteBuffer, int oldOffset, long paramsPtr) {
56-
// Free old segment
57-
if (oldOffset != -1) {
55+
public Segment allocateSegment(int size) {
56+
if (DEBUG && size % elementSize != 0)
57+
throw new RuntimeException("Unaligned buffer");
58+
59+
Segment segment = findSegment(size);
60+
61+
if (segment.size - size > 0) {
62+
Segment s1 = new Segment(segment.offset + size, segment.size - size);
63+
segments++;
64+
65+
if (segment.next != null) {
66+
s1.bindNext(segment.next);
67+
} else
68+
this.last = s1;
69+
70+
segment.bindNext(s1);
71+
72+
segment.size = size;
73+
}
74+
75+
segment.free = false;
76+
this.usedSegments.put(segment.offset, segment);
77+
78+
segment.paramsPtr = 0;
79+
80+
this.used += size;
81+
82+
return segment;
83+
}
84+
85+
public void freeSegment(int offset) {
86+
if (offset != -1) {
5887
// Need to delay segment freeing since it might be still used by prev frames in flight
5988
// this.setSegmentFree(oldOffset);
60-
MemoryManager.getInstance().addToFreeSegment(this, oldOffset);
89+
MemoryManager.getInstance().addToFreeSegment(this, offset);
6190
}
91+
}
92+
93+
public void upload(Segment segment, ByteBuffer byteBuffer, int offset) {
94+
int size = byteBuffer.remaining();
95+
96+
if (DEBUG && size % elementSize != 0)
97+
throw new RuntimeException("Unaligned buffer");
98+
99+
if (size + offset > segment.size) {
100+
throw new RuntimeException("trying to upload %d at offset %d, but segment size is %d".formatted(size, offset, segment.size));
101+
}
102+
103+
Buffer dst = this.buffer;
104+
UploadManager.INSTANCE.recordUpload(dst, segment.offset + offset, size, byteBuffer);
105+
}
106+
107+
public Segment upload(ByteBuffer byteBuffer, int oldOffset, long paramsPtr) {
108+
freeSegment(oldOffset);
62109

63110
int size = byteBuffer.remaining();
64111

@@ -120,7 +167,8 @@ public Segment reallocate(int uploadSize) {
120167
int minIncrement = this.size >> 3;
121168
minIncrement = (int) Util.align(minIncrement, this.elementSize);
122169

123-
int increment = Math.max(minIncrement, uploadSize << 1);
170+
// int increment = Math.max(minIncrement, uploadSize << 1);
171+
int increment = Math.max(minIncrement, uploadSize);
124172

125173
if (increment < uploadSize)
126174
throw new RuntimeException(String.format("Size increment %d < %d (Upload size)", increment, uploadSize));

src/main/java/net/vulkanmod/render/chunk/buffer/DrawBuffers.java

Lines changed: 114 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
public class DrawBuffers {
2727
public static final int VERTEX_SIZE = PipelineManager.terrainVertexFormat.getVertexSize();
2828
public static final int INDEX_SIZE = Short.BYTES;
29+
public static final int UNDEFINED_FACING_IDX = QuadFacing.UNDEFINED.ordinal();
30+
public static final float POS_OFFSET = CustomVertexFormat.getPositionOffset();
2931

3032
private static final int CMD_STRIDE = 32;
3133

@@ -43,7 +45,7 @@ public class DrawBuffers {
4345
final int[] sectionIndices = new int[512];
4446
final int[] masks = new int[512];
4547

46-
//Need ugly minHeight Parameter to fix custom world heights (exceeding 384 Blocks in total)
48+
// Need ugly minHeight parameter to fix custom world heights (exceeding 384 Blocks in total)
4749
public DrawBuffers(int index, Vector3i origin, int minHeight) {
4850
this.index = index;
4951
this.origin = origin;
@@ -71,23 +73,50 @@ public void upload(RenderSection section, UploadBuffer buffer, TerrainRenderType
7173
return;
7274
}
7375

76+
int oldOffset = -1;
77+
int size = 0;
7478
for (int i = 0; i < QuadFacing.COUNT; i++) {
7579
long paramPtr = DrawParametersBuffer.getParamsPtr(this.drawParamsPtr, section.inAreaIndex, renderType.ordinal(), i);
76-
7780
int vertexOffset = DrawParametersBuffer.getVertexOffset(paramPtr);
81+
82+
// Only need to get first used offset, as it identifies the whole segment that will be freed
83+
if (oldOffset == -1) {
84+
oldOffset = vertexOffset;
85+
}
86+
87+
var vertexBuffer = vertexBuffers[i];
88+
if (vertexBuffer != null) {
89+
size += vertexBuffer.remaining();
90+
91+
}
92+
}
93+
94+
if (size == 0) {
95+
return;
96+
}
97+
98+
AreaBuffer areaBuffer = this.getAreaBufferOrAlloc(renderType);
99+
areaBuffer.freeSegment(oldOffset);
100+
AreaBuffer.Segment segment = areaBuffer.allocateSegment(size);
101+
102+
int baseInstance = encodeSectionOffset(section.xOffset(), section.yOffset(), section.zOffset());
103+
104+
int offset = 0;
105+
for (int i = 0; i < QuadFacing.COUNT; i++) {
106+
long paramPtr = DrawParametersBuffer.getParamsPtr(this.drawParamsPtr, section.inAreaIndex, renderType.ordinal(), i);
107+
108+
int vertexOffset = -1;
78109
int firstIndex = 0;
79110
int indexCount = 0;
80111

81112
var vertexBuffer = vertexBuffers[i];
82113
int vertexCount = 0;
83114

84115
if (vertexBuffer != null) {
85-
AreaBuffer.Segment segment = this.getAreaBufferOrAlloc(renderType).upload(vertexBuffer, vertexOffset, paramPtr);
86-
vertexOffset = segment.offset / VERTEX_SIZE;
87-
88-
int baseInstance = encodeSectionOffset(section.xOffset(), section.yOffset(), section.zOffset());
89-
DrawParametersBuffer.setBaseInstance(paramPtr, baseInstance);
116+
areaBuffer.upload(segment, vertexBuffer, offset);
117+
vertexOffset = (segment.offset + offset) / VERTEX_SIZE;
90118

119+
offset += vertexBuffer.remaining();
91120
vertexCount = vertexBuffer.limit() / VERTEX_SIZE;
92121
indexCount = vertexCount * 6 / 4;
93122
}
@@ -97,16 +126,17 @@ public void upload(RenderSection section, UploadBuffer buffer, TerrainRenderType
97126
this.indexBuffer = new AreaBuffer(AreaBuffer.Usage.INDEX, 60000, INDEX_SIZE);
98127
}
99128

100-
int oldOffset = DrawParametersBuffer.getIndexCount(paramPtr) > 0 ? DrawParametersBuffer.getFirstIndex(paramPtr) : -1;
101-
AreaBuffer.Segment segment = this.indexBuffer.upload(buffer.getIndexBuffer(), oldOffset, paramPtr);
102-
firstIndex = segment.offset / INDEX_SIZE;
129+
oldOffset = DrawParametersBuffer.getIndexCount(paramPtr) > 0 ? DrawParametersBuffer.getFirstIndex(paramPtr) : -1;
130+
AreaBuffer.Segment ibSegment = this.indexBuffer.upload(buffer.getIndexBuffer(), oldOffset, paramPtr);
131+
firstIndex = ibSegment.offset / INDEX_SIZE;
103132
} else {
104133
Renderer.getDrawer().getQuadsIndexBuffer().checkCapacity(vertexCount);
105134
}
106135

107136
DrawParametersBuffer.setIndexCount(paramPtr, indexCount);
108137
DrawParametersBuffer.setFirstIndex(paramPtr, firstIndex);
109138
DrawParametersBuffer.setVertexOffset(paramPtr, vertexOffset);
139+
DrawParametersBuffer.setBaseInstance(paramPtr, baseInstance);
110140
}
111141

112142
buffer.release();
@@ -140,9 +170,6 @@ private int encodeSectionOffset(int xOffset, int yOffset, int zOffset) {
140170
return yOffset1 << 16 | zOffset1 << 8 | xOffset1;
141171
}
142172

143-
// TODO: refactor
144-
public static final float POS_OFFSET = PipelineManager.terrainVertexFormat == CustomVertexFormat.COMPRESSED_TERRAIN ? 4.0f : 0.0f;
145-
146173
private void updateChunkAreaOrigin(VkCommandBuffer commandBuffer, Pipeline pipeline, double camX, double camY, double camZ, MemoryStack stack) {
147174
float xOffset = (float) ((this.origin.x) + POS_OFFSET - camX);
148175
float yOffset = (float) ((this.origin.y) + POS_OFFSET - camY);
@@ -187,26 +214,57 @@ public void buildDrawBatchesIndirect(Vec3 cameraPos, IndirectBuffer indirectBuff
187214

188215
long drawParamsBasePtr2 = drawParamsBasePtr + (sectionIdx * facingsStride);
189216

217+
int indexCount = 0;
218+
int firstIndex = 0;
219+
int vertexOffset = 0;
220+
int baseInstance = 0;
221+
190222
for (int i = 0; i < QuadFacing.COUNT; i++) {
191223

192224
if ((mask & 1 << i) == 0) {
193225
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
226+
227+
// Flush draw cmd
228+
if (indexCount > 0) {
229+
MemoryUtil.memPutInt(ptr, indexCount);
230+
MemoryUtil.memPutInt(ptr + 4, 1);
231+
MemoryUtil.memPutInt(ptr + 8, firstIndex);
232+
MemoryUtil.memPutInt(ptr + 12, vertexOffset);
233+
MemoryUtil.memPutInt(ptr + 16, baseInstance);
234+
235+
ptr += CMD_STRIDE;
236+
drawCount++;
237+
}
238+
239+
indexCount = 0;
240+
firstIndex = 0;
241+
vertexOffset = 0;
242+
baseInstance = 0;
243+
194244
continue;
195245
}
196246

197247
long drawParamsPtr = drawParamsBasePtr2;
198248

199-
final int indexCount = DrawParametersBuffer.getIndexCount(drawParamsPtr);
200-
final int firstIndex = DrawParametersBuffer.getFirstIndex(drawParamsPtr);
201-
final int vertexOffset = DrawParametersBuffer.getVertexOffset(drawParamsPtr);
202-
final int baseInstance = DrawParametersBuffer.getBaseInstance(drawParamsPtr);
249+
final int indexCount_i = DrawParametersBuffer.getIndexCount(drawParamsPtr);
250+
final int firstIndex_i = DrawParametersBuffer.getFirstIndex(drawParamsPtr);
251+
final int vertexOffset_i = DrawParametersBuffer.getVertexOffset(drawParamsPtr);
252+
final int baseInstance_i = DrawParametersBuffer.getBaseInstance(drawParamsPtr);
203253

204-
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
205-
206-
if (indexCount <= 0) {
207-
continue;
254+
if (indexCount == 0) {
255+
indexCount = indexCount_i;
256+
firstIndex = firstIndex_i;
257+
vertexOffset = vertexOffset_i;
258+
baseInstance = baseInstance_i;
259+
}
260+
else {
261+
indexCount += indexCount_i;
208262
}
209263

264+
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
265+
}
266+
267+
if (indexCount > 0) {
210268
MemoryUtil.memPutInt(ptr, indexCount);
211269
MemoryUtil.memPutInt(ptr + 4, 1);
212270
MemoryUtil.memPutInt(ptr + 8, firstIndex);
@@ -227,8 +285,7 @@ public void buildDrawBatchesIndirect(Vec3 cameraPos, IndirectBuffer indirectBuff
227285
count++;
228286
}
229287

230-
final int facing = 6;
231-
final long facingOffset = facing * DrawParametersBuffer.STRIDE;
288+
final long facingOffset = UNDEFINED_FACING_IDX * DrawParametersBuffer.STRIDE;
232289
drawParamsBasePtr += facingOffset;
233290

234291
long ptr = bufferPtr;
@@ -293,34 +350,57 @@ public void buildDrawBatchesDirect(Vec3 cameraPos, StaticQueue<RenderSection> qu
293350

294351
long drawParamsBasePtr2 = drawParamsBasePtr + (sectionIdx * facingsStride);
295352

353+
int indexCount = 0;
354+
int firstIndex = 0;
355+
int vertexOffset = 0;
356+
int baseInstance = 0;
357+
296358
for (int i = 0; i < QuadFacing.COUNT; i++) {
297359

298360
if ((mask & 1 << i) == 0) {
299361
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
362+
363+
// Flush draw cmd
364+
if (indexCount > 0) {
365+
vkCmdDrawIndexed(commandBuffer, indexCount, 1, firstIndex, vertexOffset, baseInstance);
366+
}
367+
368+
indexCount = 0;
369+
firstIndex = 0;
370+
vertexOffset = 0;
371+
baseInstance = 0;
372+
300373
continue;
301374
}
302375

303376
long drawParamsPtr = drawParamsBasePtr2;
304377

305-
final int indexCount = DrawParametersBuffer.getIndexCount(drawParamsPtr);
306-
final int firstIndex = DrawParametersBuffer.getFirstIndex(drawParamsPtr);
307-
final int vertexOffset = DrawParametersBuffer.getVertexOffset(drawParamsPtr);
308-
final int baseInstance = DrawParametersBuffer.getBaseInstance(drawParamsPtr);
309-
310-
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
378+
final int indexCount_i = DrawParametersBuffer.getIndexCount(drawParamsPtr);
379+
final int firstIndex_i = DrawParametersBuffer.getFirstIndex(drawParamsPtr);
380+
final int vertexOffset_i = DrawParametersBuffer.getVertexOffset(drawParamsPtr);
381+
final int baseInstance_i = DrawParametersBuffer.getBaseInstance(drawParamsPtr);
311382

312-
if (indexCount <= 0) {
313-
continue;
383+
if (indexCount == 0) {
384+
indexCount = indexCount_i;
385+
firstIndex = firstIndex_i;
386+
vertexOffset = vertexOffset_i;
387+
baseInstance = baseInstance_i;
388+
}
389+
else {
390+
indexCount += indexCount_i;
314391
}
315392

393+
drawParamsBasePtr2 += DrawParametersBuffer.STRIDE;
394+
}
395+
396+
if (indexCount > 0) {
316397
vkCmdDrawIndexed(commandBuffer, indexCount, 1, firstIndex, vertexOffset, baseInstance);
317398
}
318399
}
319400

320401
}
321402
else {
322-
final int facing = 6;
323-
final long facingOffset = facing * DrawParametersBuffer.STRIDE;
403+
final long facingOffset = UNDEFINED_FACING_IDX * DrawParametersBuffer.STRIDE;
324404
drawParamsBasePtr += facingOffset;
325405

326406
for (var iterator = queue.iterator(isTranslucent); iterator.hasNext(); ) {
@@ -354,7 +434,7 @@ private int getMask(Vec3 camera, RenderSection section) {
354434
final int secY = section.yOffset;
355435
final int secZ = section.zOffset;
356436

357-
int mask = 1 << QuadFacing.UNDEFINED.ordinal();
437+
int mask = 1 << UNDEFINED_FACING_IDX;
358438

359439
mask |= camera.x - secX >= 0 ? 1 << QuadFacing.X_POS.ordinal() : 0;
360440
mask |= camera.y - secY >= 0 ? 1 << QuadFacing.Y_POS.ordinal() : 0;

src/main/java/net/vulkanmod/render/chunk/cull/QuadFacing.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88
public enum QuadFacing {
99
X_POS,
10-
X_NEG,
1110
Y_POS,
12-
Y_NEG,
1311
Z_POS,
12+
X_NEG,
1413
Z_NEG,
15-
UNDEFINED;
14+
UNDEFINED,
15+
Y_NEG;
1616

1717
public static final QuadFacing[] VALUES = QuadFacing.values();
1818
public static final int COUNT = VALUES.length;

src/main/java/net/vulkanmod/render/vertex/CustomVertexFormat.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import com.mojang.blaze3d.vertex.VertexFormat;
44
import com.mojang.blaze3d.vertex.VertexFormatElement;
55

6-
public class CustomVertexFormat {
7-
6+
public abstract class CustomVertexFormat {
87
public static final VertexFormatElement ELEMENT_POSITION = new VertexFormatElement(0, 0,VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.POSITION, 4);
98
public static final VertexFormatElement ELEMENT_COLOR = new VertexFormatElement(1, 0, VertexFormatElement.Type.UINT, VertexFormatElement.Usage.COLOR, 1);
109
public static final VertexFormatElement ELEMENT_UV0 = new VertexFormatElement(2, 0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.UV, 2);
1110

11+
private static float POSITION_OFFSET = 4.0f;
12+
1213
public static final VertexFormat COMPRESSED_TERRAIN =
1314
VertexFormat.builder()
1415
.add("Position", ELEMENT_POSITION)
@@ -17,4 +18,12 @@ public class CustomVertexFormat {
1718
.build();
1819

1920
public static final VertexFormat NONE = VertexFormat.builder().build();
21+
22+
public static void setPositionOffset(float positionOffset) {
23+
POSITION_OFFSET = positionOffset;
24+
}
25+
26+
public static float getPositionOffset() {
27+
return POSITION_OFFSET;
28+
}
2029
}

0 commit comments

Comments
 (0)