Fix #244 and improve performance of light updates.

This commit is contained in:
IntegratedQuantum 2023-12-23 20:22:02 +01:00
parent 4330f33d36
commit e8f62d5660

View File

@ -49,6 +49,17 @@ pub const ChannelChunk = struct {
value: u8, value: u8,
}; };
const PositionEntry = struct {
x: u5,
y: u5,
z: u5,
};
const ChunkEntries = struct {
mesh: ?*chunk.meshing.ChunkMesh,
entries: std.ArrayListUnmanaged(PositionEntry),
};
fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry)) std.mem.Allocator.Error!void { fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry)) std.mem.Allocator.Error!void {
var neighborLists: [6]std.ArrayListUnmanaged(Entry) = .{.{}} ** 6; var neighborLists: [6]std.ArrayListUnmanaged(Entry) = .{.{}} ** 6;
defer { defer {
@ -96,10 +107,9 @@ pub const ChannelChunk = struct {
} }
} }
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry)) std.mem.Allocator.Error!void { fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *std.ArrayListUnmanaged(ChunkEntries)) std.mem.Allocator.Error!std.ArrayListUnmanaged(PositionEntry) {
var neighborLists: [6]std.ArrayListUnmanaged(Entry) = .{.{}} ** 6; var neighborLists: [6]std.ArrayListUnmanaged(Entry) = .{.{}} ** 6;
var constructiveList: std.ArrayListUnmanaged(Entry) = .{}; var constructiveList: std.ArrayListUnmanaged(PositionEntry) = .{};
defer constructiveList.deinit(main.globalAllocator);
defer { defer {
for(&neighborLists) |*list| { for(&neighborLists) |*list| {
list.deinit(main.globalAllocator); list.deinit(main.globalAllocator);
@ -111,8 +121,9 @@ pub const ChannelChunk = struct {
while(lightQueue.dequeue()) |entry| { while(lightQueue.dequeue()) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z); const index = chunk.getIndex(entry.x, entry.y, entry.z);
if(entry.value != self.data[index].load(.Unordered)) { if(entry.value != self.data[index].load(.Unordered)) {
try constructiveList.append(main.globalAllocator, .{.x = entry.x, .y = entry.y, .z = entry.z, .value = self.data[index].load(.Unordered)}); if(self.data[index].load(.Unordered) != 0) {
self.data[index].store(0, .Unordered); try constructiveList.append(main.globalAllocator, .{.x = entry.x, .y = entry.y, .z = entry.z});
}
continue; continue;
} }
self.data[index].store(0, .Unordered); self.data[index].store(0, .Unordered);
@ -144,14 +155,13 @@ pub const ChannelChunk = struct {
for(0..6) |neighbor| { for(0..6) |neighbor| {
if(neighborLists[neighbor].items.len == 0) continue; if(neighborLists[neighbor].items.len == 0) continue;
const neighborMesh = main.renderer.RenderStructure.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue; const neighborMesh = main.renderer.RenderStructure.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
defer neighborMesh.decreaseRefCount(); try constructiveEntries.append(main.globalAllocator, .{
try neighborMesh.lightingData[@intFromEnum(self.channel)].propagateDestructiveFromNeighbor(neighborLists[neighbor].items); .mesh = neighborMesh,
.entries = try neighborMesh.lightingData[@intFromEnum(self.channel)].propagateDestructiveFromNeighbor(neighborLists[neighbor].items, constructiveEntries),
});
} }
for(constructiveList.items) |entry| { return constructiveList;
try lightQueue.enqueue(entry);
}
try self.propagateDirect(lightQueue);
} }
fn propagateFromNeighbor(self: *ChannelChunk, lights: []const Entry) std.mem.Allocator.Error!void { fn propagateFromNeighbor(self: *ChannelChunk, lights: []const Entry) std.mem.Allocator.Error!void {
@ -168,7 +178,7 @@ pub const ChannelChunk = struct {
try self.propagateDirect(&lightQueue); try self.propagateDirect(&lightQueue);
} }
fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lights: []const Entry) std.mem.Allocator.Error!void { fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lights: []const Entry, constructiveEntries: *std.ArrayListUnmanaged(ChunkEntries)) std.mem.Allocator.Error!std.ArrayListUnmanaged(PositionEntry) {
var lightQueue = try main.utils.CircularBufferQueue(Entry).init(main.globalAllocator, 1 << 8); var lightQueue = try main.utils.CircularBufferQueue(Entry).init(main.globalAllocator, 1 << 8);
defer lightQueue.deinit(); defer lightQueue.deinit();
for(lights) |entry| { for(lights) |entry| {
@ -179,7 +189,7 @@ pub const ChannelChunk = struct {
result.value -|= absorption; result.value -|= absorption;
if(result.value != 0) try lightQueue.enqueue(result); if(result.value != 0) try lightQueue.enqueue(result);
} }
try self.propagateDestructive(&lightQueue); return try self.propagateDestructive(&lightQueue, constructiveEntries);
} }
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) std.mem.Allocator.Error!void { pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) std.mem.Allocator.Error!void {
@ -247,6 +257,26 @@ pub const ChannelChunk = struct {
const index = chunk.getIndex(pos[0], pos[1], pos[2]); const index = chunk.getIndex(pos[0], pos[1], pos[2]);
try lightQueue.enqueue(.{.x = @intCast(pos[0]), .y = @intCast(pos[1]), .z = @intCast(pos[2]), .value = self.data[index].load(.Unordered)}); try lightQueue.enqueue(.{.x = @intCast(pos[0]), .y = @intCast(pos[1]), .z = @intCast(pos[2]), .value = self.data[index].load(.Unordered)});
} }
try self.propagateDestructive(&lightQueue); var constructiveEntries: std.ArrayListUnmanaged(ChunkEntries) = .{};
defer constructiveEntries.deinit(main.globalAllocator);
try constructiveEntries.append(main.globalAllocator, .{
.mesh = null,
.entries = try self.propagateDestructive(&lightQueue, &constructiveEntries),
});
for(constructiveEntries.items) |entries| {
const mesh = entries.mesh;
defer if(mesh) |_mesh| _mesh.decreaseRefCount();
var entryList = entries.entries;
defer entryList.deinit(main.globalAllocator);
const channelChunk = if(mesh) |_mesh| &_mesh.lightingData[@intFromEnum(self.channel)] else self;
for(entryList.items) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z);
const value = channelChunk.data[index].load(.Unordered);
if(value == 0) continue;
channelChunk.data[index].store(0, .Unordered);
try lightQueue.enqueue(.{.x = entry.x, .y = entry.y, .z = entry.z, .value = value});
}
try channelChunk.propagateDirect(&lightQueue);
}
} }
}; };