Remove redundant light refreshes.

helps with #277
This commit is contained in:
IntegratedQuantum 2024-06-27 22:49:22 +02:00
parent d40da846a0
commit 04f9bae91c
2 changed files with 81 additions and 46 deletions

View File

@ -717,12 +717,8 @@ pub const ChunkMesh = struct {
}
}
pub fn scheduleLightRefreshAndDecreaseRefCount(self: *ChunkMesh) void {
if(!self.needsLightRefresh.swap(true, .acq_rel)) {
LightRefreshTask.scheduleAndDecreaseRefCount(self);
} else {
self.decreaseRefCount();
}
pub fn scheduleLightRefreshAndDecreaseRefCount1(self: *ChunkMesh) void {
LightRefreshTask.scheduleAndDecreaseRefCount(self);
}
const LightRefreshTask = struct {
mesh: *ChunkMesh,
@ -783,7 +779,7 @@ pub const ChunkMesh = struct {
);
}
fn initLight(self: *ChunkMesh) void {
fn initLight(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
self.mutex.lock();
var lightEmittingBlocks = main.List([3]u8).init(main.stackAllocator);
defer lightEmittingBlocks.deinit();
@ -799,7 +795,7 @@ pub const ChunkMesh = struct {
}
}
self.mutex.unlock();
self.lightingData[0].propagateLights(lightEmittingBlocks.items, true);
self.lightingData[0].propagateLights(lightEmittingBlocks.items, true, lightRefreshList);
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;
@ -821,9 +817,9 @@ pub const ChunkMesh = struct {
}
}
if(allSun) {
self.lightingData[1].propagateUniformSun();
self.lightingData[1].propagateUniformSun(lightRefreshList);
} else {
self.lightingData[1].propagateLights(sunStarters[0..index], true);
self.lightingData[1].propagateLights(sunStarters[0..index], true, lightRefreshList);
}
}
}
@ -835,7 +831,9 @@ pub const ChunkMesh = struct {
self.mutex.unlock();
try mesh_storage.addMeshToStorage(self);
self.initLight();
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
defer lightRefreshList.deinit();
self.initLight(&lightRefreshList);
self.mutex.lock();
self.finishedLighting = true;
@ -858,20 +856,28 @@ pub const ChunkMesh = struct {
const shiftSelf: u5 = @intCast(((dx + 1)*3 + dy + 1)*3 + dz + 1);
const shiftOther: u5 = @intCast(((-dx + 1)*3 + -dy + 1)*3 + -dz + 1);
if(neighborMesh.litNeighbors.fetchOr(@as(u27, 1) << shiftOther, .monotonic) ^ @as(u27, 1) << shiftOther == ~@as(u27, 0)) { // Trigger mesh creation for neighbor
neighborMesh.generateMesh();
neighborMesh.generateMesh(&lightRefreshList);
}
neighborMesh.mutex.lock();
const neighborFinishedLighting = neighborMesh.finishedLighting;
neighborMesh.mutex.unlock();
if(neighborFinishedLighting and self.litNeighbors.fetchOr(@as(u27, 1) << shiftSelf, .monotonic) ^ @as(u27, 1) << shiftSelf == ~@as(u27, 0)) {
self.generateMesh();
self.generateMesh(&lightRefreshList);
}
}
}
}
for(lightRefreshList.items) |other| {
if(other.needsLightRefresh.load(.unordered)) {
other.scheduleLightRefreshAndDecreaseRefCount1();
} else {
other.decreaseRefCount();
}
}
}
pub fn generateMesh(self: *ChunkMesh) void {
pub fn generateMesh(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
var canSeeNeighbor: [6][chunk.chunkSize][chunk.chunkSize]u32 = undefined;
@memset(std.mem.asBytes(&canSeeNeighbor), 0);
var canSeeAllNeighbors: [chunk.chunkSize][chunk.chunkSize]u32 = undefined;
@ -1108,23 +1114,32 @@ pub const ChunkMesh = struct {
}
self.mutex.unlock();
self.finishNeighbors();
self.finishNeighbors(lightRefreshList);
}
fn updateBlockLight(self: *ChunkMesh, x: u5, y: u5, z: u5, newBlock: Block) void {
fn updateBlockLight(self: *ChunkMesh, x: u5, y: u5, z: u5, newBlock: Block, lightRefreshList: *main.List(*ChunkMesh)) void {
for(self.lightingData[0..]) |lightingData| {
lightingData.propagateLightsDestructive(&.{.{x, y, z}});
lightingData.propagateLightsDestructive(&.{.{x, y, z}}, lightRefreshList);
}
if(newBlock.light() != 0) {
self.lightingData[0].propagateLights(&.{.{x, y, z}}, false);
self.lightingData[0].propagateLights(&.{.{x, y, z}}, false, lightRefreshList);
}
}
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, _newBlock: Block) void {
std.log.err("Block: {} {} {}", .{_x, _y, _z});
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
defer lightRefreshList.deinit();
const x: u5 = @intCast(_x & chunk.chunkMask);
const y: u5 = @intCast(_y & chunk.chunkMask);
const z: u5 = @intCast(_z & chunk.chunkMask);
var newBlock = _newBlock;
self.mutex.lock();
if(std.meta.eql(self.chunk.data.getValue(chunk.getIndex(x, y, z)), newBlock)) {
self.mutex.unlock();
return;
}
self.mutex.unlock();
var neighborBlocks: [6]Block = undefined;
@memset(&neighborBlocks, .{.typ = 0, .data = 0});
for(chunk.Neighbors.iterable) |neighbor| {
@ -1143,8 +1158,8 @@ pub const ChunkMesh = struct {
neighborChunkMesh.opaqueMesh.coreFaces.clearRetainingCapacity();
neighborChunkMesh.transparentMesh.coreFaces.clearRetainingCapacity();
neighborChunkMesh.mutex.unlock();
neighborChunkMesh.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock);
neighborChunkMesh.generateMesh();
neighborChunkMesh.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
neighborChunkMesh.generateMesh(&lightRefreshList);
neighborChunkMesh.mutex.lock();
}
}
@ -1157,7 +1172,7 @@ pub const ChunkMesh = struct {
if(neighborBlock.mode().dependsOnNeighbors) {
if(neighborBlock.mode().updateData(&neighborBlock, neighbor ^ 1, newBlock)) {
self.chunk.data.setValue(index, neighborBlock);
self.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock);
self.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
}
}
self.mutex.unlock();
@ -1172,7 +1187,7 @@ pub const ChunkMesh = struct {
self.mutex.lock();
self.chunk.data.setValue(chunk.getIndex(x, y, z), newBlock);
self.mutex.unlock();
self.updateBlockLight(x, y, z, newBlock);
self.updateBlockLight(x, y, z, newBlock, &lightRefreshList);
self.mutex.lock();
defer self.mutex.unlock();
// Update neighbor chunks:
@ -1200,8 +1215,15 @@ pub const ChunkMesh = struct {
self.opaqueMesh.coreFaces.clearRetainingCapacity();
self.transparentMesh.coreFaces.clearRetainingCapacity();
self.mutex.unlock();
self.generateMesh(); // TODO: Batch mesh updates instead of applying them for each block changes.
self.generateMesh(&lightRefreshList); // TODO: Batch mesh updates instead of applying them for each block changes.
self.mutex.lock();
for(lightRefreshList.items) |other| {
if(other.needsLightRefresh.load(.unordered)) {
other.scheduleLightRefreshAndDecreaseRefCount1();
} else {
other.decreaseRefCount();
}
}
self.uploadData();
}
@ -1241,7 +1263,7 @@ pub const ChunkMesh = struct {
}
}
fn finishNeighbors(self: *ChunkMesh) void {
fn finishNeighbors(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
for(chunk.Neighbors.iterable) |neighbor| {
const nullNeighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.pos, self.pos.voxelSize, neighbor);
if(nullNeighborMesh) |neighborMesh| sameLodBlock: {
@ -1303,10 +1325,9 @@ pub const ChunkMesh = struct {
}
}
}
_ = neighborMesh.needsLightRefresh.swap(false, .acq_rel);
neighborMesh.finishData();
_ = neighborMesh.needsLightRefresh.store(true, .release);
neighborMesh.increaseRefCount();
mesh_storage.addToUpdateListAndDecreaseRefCount(neighborMesh);
lightRefreshList.append(neighborMesh);
} else {
self.mutex.lock();
defer self.mutex.unlock();

View File

@ -103,7 +103,7 @@ pub const ChannelChunk = struct {
}
}
fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry)) void {
fn propagateDirect(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6;
defer {
for(&neighborLists) |*list| {
@ -146,19 +146,26 @@ pub const ChannelChunk = struct {
}
self.data.optimizeLayout();
self.lock.unlockWrite();
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
mesh.scheduleLightRefreshAndDecreaseRefCount();
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
for(lightRefreshList.items) |other| {
if(mesh == other) {
mesh.decreaseRefCount();
break :outer;
}
}
mesh.needsLightRefresh.store(true, .release);
lightRefreshList.append(mesh);
}
for(0..6) |neighbor| {
if(neighborLists[neighbor].items.len == 0) continue;
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
defer neighborMesh.decreaseRefCount();
neighborMesh.lightingData[@intFromBool(self.isSun)].propagateFromNeighbor(lightQueue, neighborLists[neighbor].items);
neighborMesh.lightingData[@intFromBool(self.isSun)].propagateFromNeighbor(lightQueue, neighborLists[neighbor].items, lightRefreshList);
}
}
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool) main.ListUnmanaged(PositionEntry) {
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6;
var constructiveList: main.ListUnmanaged(PositionEntry) = .{};
defer {
@ -224,8 +231,15 @@ pub const ChannelChunk = struct {
}
}
self.lock.unlockWrite();
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
mesh.scheduleLightRefreshAndDecreaseRefCount();
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
for(lightRefreshList.items) |other| {
if(mesh == other) {
mesh.decreaseRefCount();
break :outer;
}
}
mesh.needsLightRefresh.store(true, .release);
lightRefreshList.append(mesh);
}
for(0..6) |neighbor| {
@ -233,14 +247,14 @@ pub const ChannelChunk = struct {
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
constructiveEntries.append(main.stackAllocator, .{
.mesh = neighborMesh,
.entries = neighborMesh.lightingData[@intFromBool(self.isSun)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries),
.entries = neighborMesh.lightingData[@intFromBool(self.isSun)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries, lightRefreshList),
});
}
return constructiveList;
}
fn propagateFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry) void {
fn propagateFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
std.debug.assert(lightQueue.startIndex == lightQueue.endIndex);
for(lights) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z);
@ -248,10 +262,10 @@ pub const ChannelChunk = struct {
calculateIncomingOcclusion(&result.value, self.ch.data.getValue(index), self.ch.pos.voxelSize, entry.sourceDir);
if(result.value[0] != 0 or result.value[1] != 0 or result.value[2] != 0) lightQueue.enqueue(result);
}
self.propagateDirect(lightQueue);
self.propagateDirect(lightQueue, lightRefreshList);
}
fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, constructiveEntries: *main.ListUnmanaged(ChunkEntries)) main.ListUnmanaged(PositionEntry) {
fn propagateDestructiveFromNeighbor(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), lights: []const Entry, constructiveEntries: *main.ListUnmanaged(ChunkEntries), lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
std.debug.assert(lightQueue.startIndex == lightQueue.endIndex);
for(lights) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z);
@ -259,10 +273,10 @@ pub const ChannelChunk = struct {
calculateIncomingOcclusion(&result.value, self.ch.data.getValue(index), self.ch.pos.voxelSize, entry.sourceDir);
lightQueue.enqueue(result);
}
return self.propagateDestructive(lightQueue, constructiveEntries, false);
return self.propagateDestructive(lightQueue, constructiveEntries, false, lightRefreshList);
}
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) void {
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();
for(lights) |pos| {
@ -320,10 +334,10 @@ pub const ChannelChunk = struct {
}
}
}
self.propagateDirect(&lightQueue);
self.propagateDirect(&lightQueue, lightRefreshList);
}
pub fn propagateUniformSun(self: *ChannelChunk) void {
pub fn propagateUniformSun(self: *ChannelChunk, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
std.debug.assert(self.isSun);
self.lock.lockWrite();
if(self.data.paletteLength != 1) {
@ -367,11 +381,11 @@ pub const ChannelChunk = struct {
entry.sourceDir = neighbor ^ 1;
}
}
neighborMesh.lightingData[1].propagateFromNeighbor(&lightQueue, &list);
neighborMesh.lightingData[1].propagateFromNeighbor(&lightQueue, &list, lightRefreshList);
}
}
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8) void {
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();
self.lock.lockRead();
@ -384,7 +398,7 @@ pub const ChannelChunk = struct {
defer constructiveEntries.deinit(main.stackAllocator);
constructiveEntries.append(main.stackAllocator, .{
.mesh = null,
.entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true),
.entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true, lightRefreshList),
});
for(constructiveEntries.items) |entries| {
const mesh = entries.mesh;
@ -401,7 +415,7 @@ pub const ChannelChunk = struct {
lightQueue.enqueue(.{.x = entry.x, .y = entry.y, .z = entry.z, .value = value, .sourceDir = 6, .activeValue = 0b111});
}
channelChunk.lock.unlockWrite();
channelChunk.propagateDirect(&lightQueue);
channelChunk.propagateDirect(&lightQueue, lightRefreshList);
}
}
};