Skip to content

Commit

Permalink
Some small performance improvements to the CPU-side mesh traversal.
Browse files Browse the repository at this point in the history
Should help implementing #526
  • Loading branch information
IntegratedQuantum committed Sep 15, 2024
1 parent bfea4d9 commit d7055f6
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/renderer/chunk_meshing.zig
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
refCount: std.atomic.Value(u32) = .init(1),
needsLightRefresh: std.atomic.Value(bool) = .init(false),
needsMeshUpdate: bool = false,
finishedMeshing: bool = false,
finishedMeshing: bool = false, // Must be synced with node.finishedMeshing in mesh_storage.zig
finishedLighting: bool = false,
litNeighbors: Atomic(u32) = .init(0),
mutex: std.Thread.Mutex = .{},
Expand Down
44 changes: 16 additions & 28 deletions src/renderer/mesh_storage.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const ChunkMeshNode = struct {
max: Vec2f = undefined,
active: bool = false,
rendered: bool = false,
finishedMeshing: bool = false, // Must be synced with mesh.finishedMeshing
mutex: std.Thread.Mutex = .{},
};
const storageSize = 64;
Expand Down Expand Up @@ -323,6 +324,7 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: i32) void {
node.mutex.lock();
const oldMesh = node.mesh;
node.mesh = null;
node.finishedMeshing = false;
node.mutex.unlock();
if(oldMesh) |mesh| {
mesh.decreaseRefCount();
Expand Down Expand Up @@ -592,9 +594,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
var lod: u3 = 0;
while(lod <= settings.highestLOD) : (lod += 1) {
const node = getNodePointer(firstPos);
node.mutex.lock();
const hasMesh = node.mesh != null and node.mesh.?.finishedMeshing;
node.mutex.unlock();
const hasMesh = node.finishedMeshing;
if(hasMesh) {
node.lod = lod;
node.min = @splat(-1);
Expand All @@ -617,6 +617,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
defer nodeList.deinit();
const projRotMat = game.projectionMatrix.mul(game.camera.viewMatrix);
while(searchList.removeOrNull()) |data| {
std.debug.assert(data.node.finishedMeshing);
nodeList.append(data.node);
data.node.active = false;

Expand All @@ -625,10 +626,6 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
mutex.unlock();
continue;
};
if(!mesh.finishedMeshing) {
mutex.unlock();
continue;
}
mesh.increaseRefCount();
defer mesh.decreaseRefCount();
mutex.unlock();
Expand All @@ -638,10 +635,10 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
const relPosFloat: Vec3f = @floatCast(relPos);
var isNeighborLod: [6]bool = .{false} ** 6;
for(chunk.Neighbor.iterable) |neighbor| continueNeighborLoop: {
const component = neighbor.extractDirectionComponent(relPos);
if(neighbor.isPositive() and component + @as(f64, @floatFromInt(chunk.chunkSize*mesh.pos.voxelSize)) <= 0) continue;
const component = neighbor.extractDirectionComponent(relPosFloat);
if(neighbor.isPositive() and component + @as(f32, @floatFromInt(chunk.chunkSize*mesh.pos.voxelSize)) <= 0) continue;
if(!neighbor.isPositive() and component >= 0) continue;
if(@reduce(.Or, @min(mesh.chunkBorders[neighbor.toInt()].min, mesh.chunkBorders[neighbor.toInt()].max) != mesh.chunkBorders[neighbor.toInt()].min)) continue; // There was not a single block in the chunk. TODO: Find a better solution.
if(@reduce(.Or, mesh.chunkBorders[neighbor.toInt()].max < mesh.chunkBorders[neighbor.toInt()].min)) continue; // There was not a single transparent block along the chunk border. TODO: Find a better solution.
const minVec: Vec3f = @floatFromInt(mesh.chunkBorders[neighbor.toInt()].min*@as(Vec3i, @splat(mesh.pos.voxelSize)));
const maxVec: Vec3f = @floatFromInt(mesh.chunkBorders[neighbor.toInt()].max*@as(Vec3i, @splat(mesh.pos.voxelSize)));
var xyMin: Vec2f = .{10, 10};
Expand Down Expand Up @@ -781,25 +778,21 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
.voxelSize = mesh.pos.voxelSize,
};
var lod: u3 = data.node.lod;
while(lod <= settings.highestLOD) : (lod += 1) {
lodLoop: while(lod <= settings.highestLOD) : (lod += 1) {
defer {
neighborPos.wx &= ~@as(i32, neighborPos.voxelSize*chunk.chunkSize);
neighborPos.wy &= ~@as(i32, neighborPos.voxelSize*chunk.chunkSize);
neighborPos.wz &= ~@as(i32, neighborPos.voxelSize*chunk.chunkSize);
neighborPos.voxelSize *= 2;
}
const node = getNodePointer(neighborPos);
if(getMeshAndIncreaseRefCount(neighborPos)) |neighborMesh| {
std.debug.assert(std.meta.eql(neighborPos, neighborMesh.pos));
defer neighborMesh.decreaseRefCount();
if(!neighborMesh.finishedMeshing) continue;
if(node.finishedMeshing) {
// Ensure that there are no high-to-low lod transitions, which would produce cracks.
if(lod == data.node.lod and lod != settings.highestLOD and !node.rendered) {
var isValid: bool = true;
const relPos2: Vec3d = @as(Vec3d, @floatFromInt(Vec3i{neighborPos.wx, neighborPos.wy, neighborPos.wz})) - playerPos;
for(chunk.Neighbor.iterable) |neighbor2| {
const component2 = neighbor2.extractDirectionComponent(relPos2);
if(neighbor2.isPositive() and component2 + @as(f64, @floatFromInt(chunk.chunkSize*neighborMesh.pos.voxelSize)) >= 0) continue;
if(neighbor2.isPositive() and component2 + @as(f64, @floatFromInt(chunk.chunkSize*neighborPos.voxelSize)) >= 0) continue;
if(!neighbor2.isPositive() and component2 <= 0) continue;
{ // Check the chunk of same lod:
const neighborPos2 = chunk.ChunkPosition{
Expand All @@ -822,15 +815,11 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
};
const node2 = getNodePointer(neighborPos2);
if(node2.rendered) {
isValid = false;
break;
isNeighborLod[neighbor.toInt()] = true;
continue :lodLoop;
}
}
}
if(!isValid) {
isNeighborLod[neighbor.toInt()] = true;
continue;
}
}
if(lod != data.node.lod) {
isNeighborLod[neighbor.toInt()] = true;
Expand All @@ -845,7 +834,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
node.active = true;
searchList.add(.{
.node = node,
.distance = neighborMesh.pos.getMaxDistanceSquared(playerPos),
.distance = neighborPos.getMaxDistanceSquared(playerPos),
}) catch unreachable;
node.rendered = true;
}
Expand All @@ -857,16 +846,13 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
}
for(nodeList.items) |node| {
node.rendered = false;
if(!node.finishedMeshing) continue;

node.mutex.lock();
const mesh = node.mesh orelse {
node.mutex.unlock();
continue;
};
if(!mesh.finishedMeshing) {
node.mutex.unlock();
continue;
}
mesh.increaseRefCount();
defer mesh.decreaseRefCount();
node.mutex.unlock();
Expand Down Expand Up @@ -982,6 +968,7 @@ pub fn updateMeshes(targetTime: i64) void { // MARK: updateMeshes()
defer mutex.lock();
if(isInRenderDistance(mesh.pos)) {
const node = getNodePointer(mesh.pos);
node.finishedMeshing = true;
mesh.finishedMeshing = true;
mesh.uploadData();
node.mutex.lock();
Expand Down Expand Up @@ -1032,6 +1019,7 @@ pub fn addMeshToStorage(mesh: *chunk_meshing.ChunkMesh) error{AlreadyStored}!voi
return error.AlreadyStored;
}
node.mesh = mesh;
node.finishedMeshing = mesh.finishedMeshing;
mesh.increaseRefCount();
}
}
Expand Down

0 comments on commit d7055f6

Please sign in to comment.