Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions buildSrc/src/main/kotlin/BuildConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

object BuildConfig {
val MINECRAFT_VERSION: String = "1.21.4"
val NEOFORGE_VERSION: String = "21.4.47-beta"
val NEOFORGE_VERSION: String = "21.4.88-beta"
val FABRIC_LOADER_VERSION: String = "0.16.9"
val FABRIC_API_VERSION: String = "0.112.1+1.21.4"

// This value can be set to null to disable Parchment.
val PARCHMENT_VERSION: String? = "2024.12.07"
val PARCHMENT_VERSION: String? = "2025.01.19"

// https://semver.org/
var MOD_VERSION: String = "0.6.7-rc.1"
var MOD_VERSION: String = "0.7.0"

fun createVersionString(project: Project): String {
val builder = StringBuilder()
Expand Down
2 changes: 1 addition & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id("multiloader-base")
id("java-library")

id("fabric-loom") version ("1.8.9")
id("fabric-loom") version ("1.9.2")
}

base {
Expand Down

This file was deleted.

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 @@ -23,6 +23,7 @@ public enum ModelQuadFacing {

public static final int COUNT = VALUES.length;
public static final int DIRECTIONS = VALUES.length - 1;
public static final int UNASSIGNED_ORDINAL = ModelQuadFacing.UNASSIGNED.ordinal();

public static final int NONE = 0;
public static final int ALL = (1 << COUNT) - 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.caffeinemc.mods.sodium.client.render.chunk;

import net.caffeinemc.mods.sodium.client.SodiumClientMod;
import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexAttributeBinding;
import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
import net.caffeinemc.mods.sodium.client.gl.device.DrawCommandList;
import net.caffeinemc.mods.sodium.client.gl.device.MultiDrawBatch;
Expand All @@ -16,7 +15,6 @@
import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList;
import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints;
import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderInterface;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior;
Expand All @@ -30,14 +28,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 @@ -73,16 +68,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, useIndexedTessellation);
}

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 @@ -94,7 +92,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,8 +108,9 @@ private static void fillCommandBuffer(MultiDrawBatch batch,
ChunkRenderList renderList,
CameraTransform camera,
TerrainRenderPass pass,
boolean useBlockFaceCulling) {
batch.clear();
boolean useBlockFaceCulling,
boolean useIndexedTessellation) {
batch.isFilled = true;

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

Expand Down Expand Up @@ -150,30 +149,48 @@ private static void fillCommandBuffer(MultiDrawBatch batch,
continue;
}

if (pass.isTranslucent()) {
addIndexedDrawCommands(batch, pMeshData, slices);
// it's necessary to sometimes not the locally-indexed command generator even for indexed tessellations since
// sometimes the index buffer is shared, but not globally shared. This means that translucent sections that
// are sharing an index buffer amongst them need to use the shared index command generator since it sets the
// same element offset for each draw command and doesn't increment it. Recall that in each draw command the indexing
// of the elements needs to start at 0 and thus starting somewhere further into the shared index buffer is invalid.
// there's also the optimization that draw commands can be combined when using a shared index buffer, be it
// globally shared or just shared within the region, which isn't possible with the locally-indexed command generator.
if (useIndexedTessellation && SectionRenderDataUnsafe.isLocalIndex(pMeshData)) {
addLocalIndexedDrawCommands(batch, pMeshData, slices);
} else {
addNonIndexedDrawCommands(batch, pMeshData, slices);
addSharedIndexedDrawCommands(batch, pMeshData, slices);
}
}
}

/**
* Generates the draw commands for a chunk's meshes using the shared index buffer.
* Generates the draw commands for a chunk's meshes, where each mesh has a separate index buffer. This is used
* when rendering translucent geometry, as each geometry set needs a sorted index buffer.
*/
@SuppressWarnings("IntegerMultiplicationImplicitCastToLong")
private static void addNonIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) {
private static void addLocalIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) {
final var pElementPointer = batch.pElementPointer;
final var pBaseVertex = batch.pBaseVertex;
final var pElementCount = batch.pElementCount;

int size = batch.size;

long elementOffset = SectionRenderDataUnsafe.getBaseElement(pMeshData);
long baseVertex = SectionRenderDataUnsafe.getBaseVertex(pMeshData);

for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) {
// Uint32 -> Int32 cast is always safe and should be optimized away
MemoryUtil.memPutInt(pBaseVertex + (size << 2), (int) SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing));
MemoryUtil.memPutInt(pElementCount + (size << 2), (int) SectionRenderDataUnsafe.getElementCount(pMeshData, facing));
MemoryUtil.memPutAddress(pElementPointer + (size << Pointer.POINTER_SHIFT), 0 /* using a shared index buffer */);
final long vertexCount = SectionRenderDataUnsafe.getVertexCount(pMeshData, facing);
final long elementCount = (vertexCount >> 2) * 6;

MemoryUtil.memPutInt(pElementCount + (size << 2), UInt32.uncheckedDowncast(elementCount));
MemoryUtil.memPutInt(pBaseVertex + (size << 2), UInt32.uncheckedDowncast(baseVertex));

// * 4 to convert to bytes (the index buffer contains integers)
MemoryUtil.memPutAddress(pElementPointer + (size << Pointer.POINTER_SHIFT), elementOffset << 2);

baseVertex += vertexCount;
elementOffset += elementCount;

size += (mask >> facing) & 1;
}
Expand All @@ -182,34 +199,57 @@ private static void addNonIndexedDrawCommands(MultiDrawBatch batch, long pMeshDa
}

/**
* Generates the draw commands for a chunk's meshes, where each mesh has a separate index buffer. This is used
* when rendering translucent geometry, as each geometry set needs a sorted index buffer.
* Generates the draw commands for a chunk's meshes using the shared index buffer.
*/
@SuppressWarnings("IntegerMultiplicationImplicitCastToLong")
private static void addIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) {
private static void addSharedIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) {
final var pElementPointer = batch.pElementPointer;
final var pBaseVertex = batch.pBaseVertex;
final var pElementCount = batch.pElementCount;

int size = batch.size;

long elementOffset = SectionRenderDataUnsafe.getBaseElement(pMeshData);

for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) {
final long vertexOffset = SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing);
final long elementCount = SectionRenderDataUnsafe.getElementCount(pMeshData, facing);
// this is either zero (global shared index buffer) or the offset to the location of the shared element buffer (region shared index buffer)
final var elementOffsetBytes = SectionRenderDataUnsafe.getBaseElement(pMeshData) << 2;
final var facingList = SectionRenderDataUnsafe.getFacingList(pMeshData);

// Uint32 -> Int32 cast is always safe and should be optimized away
MemoryUtil.memPutInt(pBaseVertex + (size << 2), UInt32.uncheckedDowncast(vertexOffset));
MemoryUtil.memPutInt(pElementCount + (size << 2), UInt32.uncheckedDowncast(elementCount));
int size = batch.size;
long groupVertexCount = 0;
long baseVertex = SectionRenderDataUnsafe.getBaseVertex(pMeshData);
int lastMaskBit = 0;

for (int i = 0; i <= ModelQuadFacing.COUNT; i++) {
var maskBit = 0;
long vertexCount = 0;
if (i < ModelQuadFacing.COUNT) {
vertexCount = SectionRenderDataUnsafe.getVertexCount(pMeshData, i);

// if there's no vertexes, the mask bit is just 0
if (vertexCount != 0) {
var facing = (facingList >>> (i * 8)) & 0xFF;
maskBit = (mask >>> facing) & 1;
}
}

// * 4 to convert to bytes (the index buffer contains integers)
// the section render data storage for the indices stores the offset in indices (also called elements)
MemoryUtil.memPutAddress(pElementPointer + (size << Pointer.POINTER_SHIFT), elementOffset << 2);
if (maskBit == 0) {
if (lastMaskBit == 1) {
// delay writing out draw command if there's a zero-size group
if (i < ModelQuadFacing.COUNT && vertexCount == 0) {
continue;
}

MemoryUtil.memPutInt(pElementCount + (size << 2), UInt32.uncheckedDowncast((groupVertexCount >> 2) * 6));
MemoryUtil.memPutInt(pBaseVertex + (size << 2), UInt32.uncheckedDowncast(baseVertex));
MemoryUtil.memPutAddress(pElementPointer + (size << Pointer.POINTER_SHIFT), elementOffsetBytes);
size++;
baseVertex += groupVertexCount;
groupVertexCount = 0;
}

baseVertex += vertexCount;
} else {
groupVertexCount += vertexCount;
}

// adding the number of elements works because the index data has one index per element (which are the indices)
elementOffset += elementCount;
size += (mask >> facing) & 1;
lastMaskBit = maskBit;
}

batch.size = size;
Expand All @@ -224,7 +264,7 @@ private static void addIndexedDrawCommands(MultiDrawBatch batch, long pMeshData,
private static final int MODEL_NEG_Y = ModelQuadFacing.NEG_Y.ordinal();
private static final int MODEL_NEG_Z = ModelQuadFacing.NEG_Z.ordinal();

private static int getVisibleFaces(int originX, int originY, int originZ, int chunkX, int chunkY, int chunkZ) {
public static int getVisibleFaces(int originX, int originY, int originZ, int chunkX, int chunkY, int chunkZ) {
// This is carefully written so that we can keep everything branch-less.
//
// Normally, this would be a ridiculous way to handle the problem. But the Hotspot VM's
Expand Down Expand Up @@ -322,6 +362,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 @@ -328,9 +328,9 @@ private boolean processChunkBuildResults(ArrayList<BuilderTaskOutput> results) {
result.render.setTranslucentData(chunkBuildOutput.translucentData);
}
} else if (result instanceof ChunkSortOutput sortOutput
&& sortOutput.getTopoSorter() != null
&& sortOutput.getDynamicSorter() != null
&& result.render.getTranslucentData() instanceof DynamicTopoData data) {
this.sortTriggering.applyTriggerChanges(data, sortOutput.getTopoSorter(), result.render.getPosition(), this.cameraPosition);
this.sortTriggering.applyTriggerChanges(data, sortOutput.getDynamicSorter(), result.render.getPosition(), this.cameraPosition);
}

var job = result.render.getTaskCancellationToken();
Expand Down Expand Up @@ -678,8 +678,10 @@ public Collection<String> getDebugStrings() {

int count = 0;

long deviceUsed = 0;
long deviceAllocated = 0;
long geometryDeviceUsed = 0;
long geometryDeviceAllocated = 0;
long indexDeviceUsed = 0;
long indexDeviceAllocated = 0;

for (var region : this.regions.getLoadedRegions()) {
var resources = region.getResources();
Expand All @@ -688,15 +690,20 @@ public Collection<String> getDebugStrings() {
continue;
}

var buffer = resources.getGeometryArena();
var geometryArena = resources.getGeometryArena();
geometryDeviceUsed += geometryArena.getDeviceUsedMemory();
geometryDeviceAllocated += geometryArena.getDeviceAllocatedMemory();

deviceUsed += buffer.getDeviceUsedMemory();
deviceAllocated += buffer.getDeviceAllocatedMemory();
var indexArena = resources.getIndexArena();
indexDeviceUsed += indexArena.getDeviceUsedMemory();
indexDeviceAllocated += indexArena.getDeviceAllocatedMemory();

count++;
}

list.add(String.format("Geometry Pool: %d/%d MiB (%d buffers)", MathUtil.toMib(deviceUsed), MathUtil.toMib(deviceAllocated), count));
list.add(String.format("Pools: Geometry %d/%d MiB, Index %d/%d MiB (%d buffers)",
MathUtil.toMib(geometryDeviceUsed), MathUtil.toMib(geometryDeviceAllocated),
MathUtil.toMib(indexDeviceUsed), MathUtil.toMib(indexDeviceAllocated), count));
list.add(String.format("Transfer Queue: %s", this.regions.getStagingBuffer().toString()));

list.add(String.format("Chunk Builder: Permits=%02d (E %03d) | Busy=%02d | Total=%02d",
Expand Down
Loading