From 781ca89affd34f40aaa8e2b6189e4b854160f0e2 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Mon, 5 Feb 2024 21:33:56 +0100 Subject: [PATCH] Use `MemoryPool` for chunk and lighting data. Temporarily fixes #263 --- src/chunk.zig | 23 ++++++++++++++++- src/main.zig | 3 +++ src/network.zig | 6 ++--- src/renderer/chunk_meshing.zig | 46 ++++++++++++++++++---------------- src/renderer/lighting.zig | 27 +++++++++++++++++--- src/renderer/mesh_storage.zig | 2 +- src/server/world.zig | 5 ++-- 7 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/chunk.zig b/src/chunk.zig index 7cb3065bc..1b78276e9 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -98,6 +98,17 @@ fn extractZFromIndex(index: usize) i32 { return @intCast(index & chunkMask); } +var memoryPool: std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)) = undefined; +var memoryPoolMutex: std.Thread.Mutex = .{}; + +pub fn init() void { + memoryPool = std.heap.MemoryPoolAligned(Chunk, @alignOf(Chunk)).init(main.globalAllocator.allocator); +} + +pub fn deinit() void { + memoryPool.deinit(); +} + pub const ChunkPosition = struct { wx: i32, wy: i32, @@ -170,7 +181,10 @@ pub const Chunk = struct { widthShift: u5, mutex: std.Thread.Mutex, - pub fn init(self: *Chunk, pos: ChunkPosition) void { + pub fn init(pos: ChunkPosition) *Chunk { + memoryPoolMutex.lock(); + const self = memoryPool.create() catch unreachable; + memoryPoolMutex.unlock(); std.debug.assert((pos.voxelSize - 1 & pos.voxelSize) == 0); std.debug.assert(@mod(pos.wx, pos.voxelSize) == 0 and @mod(pos.wy, pos.voxelSize) == 0 and @mod(pos.wz, pos.voxelSize) == 0); const voxelSizeShift: u5 = @intCast(std.math.log2_int(u31, pos.voxelSize)); @@ -182,6 +196,13 @@ pub const Chunk = struct { .widthShift = voxelSizeShift + chunkShift, .mutex = std.Thread.Mutex{}, }; + return self; + } + + pub fn deinit(self: *Chunk) void { + memoryPoolMutex.lock(); + memoryPool.destroy(@alignCast(self)); + memoryPoolMutex.unlock(); } pub fn setChanged(self: *Chunk) void { diff --git a/src/main.zig b/src/main.zig index 5de9a907b..451a77ff6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -707,6 +707,9 @@ pub fn main() void { gui.init(); defer gui.deinit(); + chunk.init(); + defer chunk.deinit(); + rotation.init(); defer rotation.deinit(); diff --git a/src/network.zig b/src/network.zig index 1f750586d..6e08eebb0 100644 --- a/src/network.zig +++ b/src/network.zig @@ -743,8 +743,7 @@ pub const Protocols = struct { std.log.err("Transmission of chunk has invalid size: {}. Input data: {any}, After inflate: {any}", .{_inflatedLen, data, _inflatedData[0.._inflatedLen]}); } data = _inflatedData; - const ch = main.globalAllocator.create(chunk.Chunk); - ch.init(pos); + const ch = chunk.Chunk.init(pos); for(&ch.blocks) |*block| { block.* = Block.fromInt(std.mem.readInt(u32, data[0..4], .big)); data = data[4..]; @@ -768,8 +767,7 @@ pub const Protocols = struct { conn.sendImportant(id, data); } fn sendChunkLocally(ch: *chunk.Chunk) void { - const chunkCopy = main.globalAllocator.create(chunk.Chunk); - chunkCopy.init(ch.pos); + const chunkCopy = chunk.Chunk.init(ch.pos); @memcpy(&chunkCopy.blocks, &ch.blocks); renderer.mesh_storage.updateChunkMesh(chunkCopy); } diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index c6e755555..c563e1112 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -52,6 +52,7 @@ pub var quadsDrawn: usize = 0; pub var transparentQuadsDrawn: usize = 0; pub fn init() void { + lighting.init(); shader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs", &uniforms); transparentShader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/transparent_fragment.fs", &transparentUniforms); @@ -73,6 +74,7 @@ pub fn init() void { } pub fn deinit() void { + lighting.deinit(); shader.deinit(); transparentShader.deinit(); c.glDeleteVertexArrays(1, &vao); @@ -240,12 +242,12 @@ const PrimitiveMesh = struct { const z = (wz >> mesh.chunk.voxelSizeShift) & chunk.chunkMask; const index = chunk.getIndex(x, y, z); return .{ - mesh.lightingData.*[0].data[index].load(.Unordered), - mesh.lightingData.*[1].data[index].load(.Unordered), - mesh.lightingData.*[2].data[index].load(.Unordered), - mesh.lightingData.*[3].data[index].load(.Unordered), - mesh.lightingData.*[4].data[index].load(.Unordered), - mesh.lightingData.*[5].data[index].load(.Unordered), + mesh.lightingData[0].data[index].load(.Unordered), + mesh.lightingData[1].data[index].load(.Unordered), + mesh.lightingData[2].data[index].load(.Unordered), + mesh.lightingData[3].data[index].load(.Unordered), + mesh.lightingData[4].data[index].load(.Unordered), + mesh.lightingData[5].data[index].load(.Unordered), }; } @@ -422,7 +424,7 @@ pub const ChunkMesh = struct { pos: chunk.ChunkPosition, size: i32, chunk: *chunk.Chunk, - lightingData: *[6]lighting.ChannelChunk, + lightingData: [6]*lighting.ChannelChunk, opaqueMesh: PrimitiveMesh, transparentMesh: PrimitiveMesh, lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6, @@ -444,20 +446,20 @@ pub const ChunkMesh = struct { chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6, pub fn init(self: *ChunkMesh, pos: chunk.ChunkPosition, ch: *chunk.Chunk) void { - const lightingData = main.globalAllocator.create([6]lighting.ChannelChunk); - lightingData[0].init(ch, .sun_red); - lightingData[1].init(ch, .sun_green); - lightingData[2].init(ch, .sun_blue); - lightingData[3].init(ch, .red); - lightingData[4].init(ch, .green); - lightingData[5].init(ch, .blue); self.* = ChunkMesh{ .pos = pos, .size = chunk.chunkSize*pos.voxelSize, .opaqueMesh = .{}, .transparentMesh = .{}, .chunk = ch, - .lightingData = lightingData, + .lightingData = .{ + lighting.ChannelChunk.init(ch, .sun_red), + lighting.ChannelChunk.init(ch, .sun_green), + lighting.ChannelChunk.init(ch, .sun_blue), + lighting.ChannelChunk.init(ch, .red), + lighting.ChannelChunk.init(ch, .green), + lighting.ChannelChunk.init(ch, .blue), + }, }; } @@ -465,10 +467,12 @@ pub const ChunkMesh = struct { std.debug.assert(self.refCount.load(.Monotonic) == 0); self.opaqueMesh.deinit(); self.transparentMesh.deinit(); + self.chunk.deinit(); main.globalAllocator.free(self.currentSorting); main.globalAllocator.free(self.sortingOutputBuffer); - main.globalAllocator.destroy(self.chunk); - main.globalAllocator.destroy(self.lightingData); + for(self.lightingData) |lightingChunk| { + lightingChunk.deinit(); + } } pub fn increaseRefCount(self: *ChunkMesh) void { @@ -584,7 +588,7 @@ pub const ChunkMesh = struct { } } self.mutex.unlock(); - for(self.lightingData[3..]) |*lightingData| { + for(self.lightingData[3..]) |lightingData| { lightingData.propagateLights(lightEmittingBlocks.items, true); } sunLight: { @@ -604,7 +608,7 @@ pub const ChunkMesh = struct { } } } - for(self.lightingData[0..3]) |*lightingData| { + for(self.lightingData[0..3]) |lightingData| { lightingData.propagateLights(sunStarters[0..index], true); } } @@ -728,11 +732,11 @@ pub const ChunkMesh = struct { const oldBlock = self.chunk.blocks[chunk.getIndex(x, y, z)]; self.chunk.blocks[chunk.getIndex(x, y, z)] = newBlock; self.mutex.unlock(); - for(self.lightingData[0..]) |*lightingData| { + for(self.lightingData[0..]) |lightingData| { lightingData.propagateLightsDestructive(&.{.{@intCast(x), @intCast(y), @intCast(z)}}); } if(newBlock.light() != 0) { - for(self.lightingData[3..]) |*lightingData| { + for(self.lightingData[3..]) |lightingData| { lightingData.propagateLights(&.{.{@intCast(x), @intCast(y), @intCast(z)}}, false); } } diff --git a/src/renderer/lighting.zig b/src/renderer/lighting.zig index 0f9c1e73d..17f4317e1 100644 --- a/src/renderer/lighting.zig +++ b/src/renderer/lighting.zig @@ -31,17 +31,38 @@ const Channel = enum(u8) { } }; +var memoryPool: std.heap.MemoryPool(ChannelChunk) = undefined; +var memoryPoolMutex: std.Thread.Mutex = .{}; + +pub fn init() void { + memoryPool = std.heap.MemoryPool(ChannelChunk).init(main.globalAllocator.allocator); +} + +pub fn deinit() void { + memoryPool.deinit(); +} + pub const ChannelChunk = struct { data: [chunk.chunkVolume]Atomic(u8), mutex: std.Thread.Mutex, ch: *chunk.Chunk, channel: Channel, - pub fn init(self: *ChannelChunk, ch: *chunk.Chunk, channel: Channel) void { + pub fn init(ch: *chunk.Chunk, channel: Channel) *ChannelChunk { + memoryPoolMutex.lock(); + const self = memoryPool.create() catch unreachable; + memoryPoolMutex.unlock(); self.mutex = .{}; self.ch = ch; self.channel = channel; @memset(&self.data, Atomic(u8).init(0)); + return self; + } + + pub fn deinit(self: *ChannelChunk) void { + memoryPoolMutex.lock(); + memoryPool.destroy(self); + memoryPoolMutex.unlock(); } const Entry = struct { @@ -235,7 +256,7 @@ pub const ChannelChunk = struct { const otherZ = z+%chunk.Neighbors.relZ[neighbor] & chunk.chunkMask; const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue; defer neighborMesh.decreaseRefCount(); - const neighborLightChunk = &neighborMesh.lightingData[@intFromEnum(self.channel)]; + const neighborLightChunk = neighborMesh.lightingData[@intFromEnum(self.channel)]; const index = chunk.getIndex(x, y, z); const neighborIndex = chunk.getIndex(otherX, otherY, otherZ); var value: u8 = neighborLightChunk.data[neighborIndex].load(.Unordered); @@ -272,7 +293,7 @@ pub const ChannelChunk = struct { 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; + 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); diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index f0fd8038c..50b415408 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -1022,7 +1022,7 @@ pub const MeshGenerationTask = struct { } pub fn clean(self: *MeshGenerationTask) void { - main.globalAllocator.destroy(self.mesh); + self.mesh.deinit(); main.globalAllocator.destroy(self); } }; diff --git a/src/server/world.zig b/src/server/world.zig index 4d20af5f9..b4795305f 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -213,8 +213,7 @@ const ChunkManager = struct { } fn chunkInitFunctionForCache(pos: ChunkPosition) *Chunk { - const ch = main.globalAllocator.create(Chunk); - ch.init(pos); + const ch = Chunk.init(pos); ch.generated = true; // TODO: if(!ChunkIO.loadChunkFromFile(world, this)) { const caveMap = terrain.CaveMap.CaveMapView.init(ch); @@ -228,7 +227,7 @@ const ChunkManager = struct { } fn chunkDeinitFunctionForCache(ch: *Chunk) void { - main.globalAllocator.destroy(ch); + ch.deinit(); // TODO: Store chunk. } /// Generates a normal chunk at a given location, or if possible gets it from the cache.