Add a fast-path for sunlight propagation in uniform air chunks.

fixes #320, terrain generation in single-player is now ~30% faster.
This commit is contained in:
IntegratedQuantum 2024-06-04 14:20:25 +02:00
parent 9cacd64c4d
commit cb2c7f07c3
2 changed files with 56 additions and 1 deletions

View File

@ -702,6 +702,7 @@ pub const ChunkMesh = struct {
self.mutex.unlock();
self.lightingData[0].propagateLights(lightEmittingBlocks.items, true);
sunLight: {
var allSun: bool = self.chunk.data.paletteLength == 1 and self.chunk.data.palette[0].typ == 0;
var sunStarters: [chunk.chunkSize*chunk.chunkSize][3]u8 = undefined;
var index: usize = 0;
const lightStartMap = mesh_storage.getLightMapPieceAndIncreaseRefCount(self.pos.wx, self.pos.wy, self.pos.voxelSize) orelse break :sunLight;
@ -715,10 +716,16 @@ pub const ChunkMesh = struct {
if(relHeight < chunk.chunkSize*self.pos.voxelSize) {
sunStarters[index] = .{x, y, chunk.chunkSize-1};
index += 1;
} else {
allSun = false;
}
}
}
self.lightingData[1].propagateLights(sunStarters[0..index], true);
if(allSun) {
self.lightingData[1].propagateUniformSun();
} else {
self.lightingData[1].propagateLights(sunStarters[0..index], true);
}
}
}

View File

@ -324,6 +324,54 @@ pub const ChannelChunk = struct {
self.propagateDirect(&lightQueue);
}
pub fn propagateUniformSun(self: *ChannelChunk) void {
std.debug.assert(self.isSun);
self.mutex.lock();
if(self.data.paletteLength != 1) {
self.data.deinit();
self.data.init();
}
self.data.palette[0] = .{255, 255, 255};
self.mutex.unlock();
const val = 255 -| 8*|@as(u8, @intCast(self.ch.pos.voxelSize));
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();
for(chunk.Neighbors.iterable) |neighbor| {
if(neighbor == chunk.Neighbors.dirUp) continue;
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
defer neighborMesh.decreaseRefCount();
var list: [chunk.chunkSize*chunk.chunkSize]Entry = undefined;
for(0..chunk.chunkSize) |x| {
for(0..chunk.chunkSize) |y| {
const entry = &list[x*chunk.chunkSize + y];
switch(chunk.Neighbors.vectorComponent[neighbor]) {
.x => {
entry.x = if(chunk.Neighbors.isPositive[neighbor]) 0 else chunk.chunkSize - 1;
entry.y = @intCast(x);
entry.z = @intCast(y);
entry.value = .{val, val, val};
},
.y => {
entry.y = if(chunk.Neighbors.isPositive[neighbor]) 0 else chunk.chunkSize - 1;
entry.x = @intCast(x);
entry.z = @intCast(y);
entry.value = .{val, val, val};
},
.z => {
entry.z = if(chunk.Neighbors.isPositive[neighbor]) 0 else chunk.chunkSize - 1;
entry.x = @intCast(x);
entry.y = @intCast(y);
entry.value = .{255, 255, 255};
},
}
entry.activeValue = 0b111;
entry.sourceDir = neighbor ^ 1;
}
}
neighborMesh.lightingData[1].propagateFromNeighbor(&lightQueue, &list);
}
}
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8) void {
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();