diff --git a/src/chunk.zig b/src/chunk.zig index ad8aab4d..d64673ac 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -814,6 +814,15 @@ pub const meshing = struct { std.debug.assert(prevVal != 0); } + /// In cases where it's not certain whether the thing was cleared already. + pub fn tryIncreaseRefCount(self: *ChunkMesh) bool { + const prevVal = self.refCount.load(.Monotonic); + while(prevVal != 0) { + prevVal = self.refCount.compareAndSwap(prevVal, prevVal + 1, .Monotonic, .Monotonic) orelse return true; + } + return false; + } + pub fn decreaseRefCount(self: *ChunkMesh) !void { const prevVal = self.refCount.fetchSub(1, .Monotonic); std.debug.assert(prevVal != 0); diff --git a/src/renderer.zig b/src/renderer.zig index f8817748..71bb12ab 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const Atomic = std.atomic.Atomic; const blocks = @import("blocks.zig"); const chunk = @import("chunk.zig"); @@ -869,7 +870,7 @@ pub const MeshSelection = struct { pub const RenderStructure = struct { const ChunkMeshNode = struct { - mesh: ?*chunk.meshing.ChunkMesh, + mesh: Atomic(?*chunk.meshing.ChunkMesh), lod: u3, min: Vec2f, max: Vec2f, @@ -903,7 +904,7 @@ pub const RenderStructure = struct { for(&storageLists) |*storageList| { storageList.* = try main.globalAllocator.create([storageSize*storageSize*storageSize]ChunkMeshNode); for(storageList.*) |*val| { - val.mesh = null; + val.mesh = Atomic(?*chunk.meshing.ChunkMesh).init(null); val.rendered = false; } } @@ -947,7 +948,7 @@ pub const RenderStructure = struct { fn getBlockFromRenderThread(x: i32, y: i32, z: i32) ?blocks.Block { const node = RenderStructure.getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}); - const mesh = node.mesh orelse return null; + const mesh = node.mesh.load(.Unordered) orelse return null; const block = mesh.chunk.getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask); return block; } @@ -956,7 +957,7 @@ pub const RenderStructure = struct { var lod: u5 = 0; while(lod < settings.highestLOD) : (lod += 1) { const node = RenderStructure.getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod}); - const mesh = node.mesh orelse continue; + const mesh = node.mesh.load(.Unordered) orelse continue; const block = mesh.chunk.getBlock(x & chunk.chunkMask<= 0) continue; + if(chunk.Neighbors.isPositive[neighbor2] and component2 + @as(f64, @floatFromInt(chunk.chunkSize*neighborMesh.pos.voxelSize)) >= 0) continue; if(!chunk.Neighbors.isPositive[neighbor2] and component2 <= 0) continue; { // Check the chunk of same lod: const neighborPos2 = chunk.ChunkPosition{ @@ -1451,7 +1461,7 @@ pub const RenderStructure = struct { node.active = true; try searchList.add(.{ .node = node, - .distance = node.mesh.?.pos.getMaxDistanceSquared(playerPos), + .distance = neighborMesh.pos.getMaxDistanceSquared(playerPos), }); node.rendered = true; } @@ -1463,10 +1473,10 @@ pub const RenderStructure = struct { } for(nodeList.items) |node| { node.rendered = false; - const mesh = node.mesh.?; + const mesh = node.mesh.load(.Unordered).?; if(mesh.pos.voxelSize != @as(u31, 1) << settings.highestLOD) { const parent = getNodeFromRenderThread(.{.wx=mesh.pos.wx, .wy=mesh.pos.wy, .wz=mesh.pos.wz, .voxelSize=mesh.pos.voxelSize << 1}); - if(parent.mesh) |parentMesh| { + if(parent.mesh.load(.Unordered)) |parentMesh| { const sizeShift = chunk.chunkShift + @ctz(mesh.pos.voxelSize); const octantIndex: u3 = @intCast((mesh.pos.wx>>sizeShift & 1) | (mesh.pos.wy>>sizeShift & 1)<<1 | (mesh.pos.wz>>sizeShift & 1)<<2); parentMesh.visibilityMask &= ~(@as(u8, 1) << octantIndex); @@ -1498,7 +1508,7 @@ pub const RenderStructure = struct { for(blockUpdateList.items) |blockUpdate| { const pos = chunk.ChunkPosition{.wx=blockUpdate.x, .wy=blockUpdate.y, .wz=blockUpdate.z, .voxelSize=1}; const node = getNodeFromRenderThread(pos); - if(node.mesh) |mesh| { + if(node.mesh.load(.Unordered)) |mesh| { try mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock); } // TODO: It seems like we simply ignore the block update if we don't have the mesh yet. } @@ -1516,7 +1526,7 @@ pub const RenderStructure = struct { mutex.unlock(); defer mutex.lock(); try mesh.decreaseRefCount(); - if(getNodeFromRenderThread(mesh.pos).mesh != mesh) continue; // This mesh isn't used for rendering anymore. + if(getNodeFromRenderThread(mesh.pos).mesh.load(.Unordered) != mesh) continue; // This mesh isn't used for rendering anymore. if(!mesh.needsNeighborUpdate) continue; try mesh.uploadDataAndFinishNeighbors(); mesh.needsNeighborUpdate = false; @@ -1553,10 +1563,9 @@ pub const RenderStructure = struct { if(isInRenderDistance(mesh.pos)) { const node = getNodeFromRenderThread(mesh.pos); try mesh.uploadDataAndFinishNeighbors(); - if(node.mesh) |oldMesh| { + if(node.mesh.swap(mesh, .Monotonic)) |oldMesh| { try oldMesh.decreaseRefCount(); } - node.mesh = mesh; } else { try mesh.decreaseRefCount(); }