Use MemoryPool for chunk and lighting data.

Temporarily fixes #263
This commit is contained in:
IntegratedQuantum 2024-02-05 21:33:56 +01:00
parent 1cca3a5769
commit 781ca89aff
7 changed files with 79 additions and 33 deletions

View File

@ -98,6 +98,17 @@ fn extractZFromIndex(index: usize) i32 {
return @intCast(index & chunkMask); 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 { pub const ChunkPosition = struct {
wx: i32, wx: i32,
wy: i32, wy: i32,
@ -170,7 +181,10 @@ pub const Chunk = struct {
widthShift: u5, widthShift: u5,
mutex: std.Thread.Mutex, 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((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); 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)); const voxelSizeShift: u5 = @intCast(std.math.log2_int(u31, pos.voxelSize));
@ -182,6 +196,13 @@ pub const Chunk = struct {
.widthShift = voxelSizeShift + chunkShift, .widthShift = voxelSizeShift + chunkShift,
.mutex = std.Thread.Mutex{}, .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 { pub fn setChanged(self: *Chunk) void {

View File

@ -707,6 +707,9 @@ pub fn main() void {
gui.init(); gui.init();
defer gui.deinit(); defer gui.deinit();
chunk.init();
defer chunk.deinit();
rotation.init(); rotation.init();
defer rotation.deinit(); defer rotation.deinit();

View File

@ -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]}); std.log.err("Transmission of chunk has invalid size: {}. Input data: {any}, After inflate: {any}", .{_inflatedLen, data, _inflatedData[0.._inflatedLen]});
} }
data = _inflatedData; data = _inflatedData;
const ch = main.globalAllocator.create(chunk.Chunk); const ch = chunk.Chunk.init(pos);
ch.init(pos);
for(&ch.blocks) |*block| { for(&ch.blocks) |*block| {
block.* = Block.fromInt(std.mem.readInt(u32, data[0..4], .big)); block.* = Block.fromInt(std.mem.readInt(u32, data[0..4], .big));
data = data[4..]; data = data[4..];
@ -768,8 +767,7 @@ pub const Protocols = struct {
conn.sendImportant(id, data); conn.sendImportant(id, data);
} }
fn sendChunkLocally(ch: *chunk.Chunk) void { fn sendChunkLocally(ch: *chunk.Chunk) void {
const chunkCopy = main.globalAllocator.create(chunk.Chunk); const chunkCopy = chunk.Chunk.init(ch.pos);
chunkCopy.init(ch.pos);
@memcpy(&chunkCopy.blocks, &ch.blocks); @memcpy(&chunkCopy.blocks, &ch.blocks);
renderer.mesh_storage.updateChunkMesh(chunkCopy); renderer.mesh_storage.updateChunkMesh(chunkCopy);
} }

View File

@ -52,6 +52,7 @@ pub var quadsDrawn: usize = 0;
pub var transparentQuadsDrawn: usize = 0; pub var transparentQuadsDrawn: usize = 0;
pub fn init() void { pub fn init() void {
lighting.init();
shader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs", &uniforms); 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); 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 { pub fn deinit() void {
lighting.deinit();
shader.deinit(); shader.deinit();
transparentShader.deinit(); transparentShader.deinit();
c.glDeleteVertexArrays(1, &vao); c.glDeleteVertexArrays(1, &vao);
@ -240,12 +242,12 @@ const PrimitiveMesh = struct {
const z = (wz >> mesh.chunk.voxelSizeShift) & chunk.chunkMask; const z = (wz >> mesh.chunk.voxelSizeShift) & chunk.chunkMask;
const index = chunk.getIndex(x, y, z); const index = chunk.getIndex(x, y, z);
return .{ return .{
mesh.lightingData.*[0].data[index].load(.Unordered), mesh.lightingData[0].data[index].load(.Unordered),
mesh.lightingData.*[1].data[index].load(.Unordered), mesh.lightingData[1].data[index].load(.Unordered),
mesh.lightingData.*[2].data[index].load(.Unordered), mesh.lightingData[2].data[index].load(.Unordered),
mesh.lightingData.*[3].data[index].load(.Unordered), mesh.lightingData[3].data[index].load(.Unordered),
mesh.lightingData.*[4].data[index].load(.Unordered), mesh.lightingData[4].data[index].load(.Unordered),
mesh.lightingData.*[5].data[index].load(.Unordered), mesh.lightingData[5].data[index].load(.Unordered),
}; };
} }
@ -422,7 +424,7 @@ pub const ChunkMesh = struct {
pos: chunk.ChunkPosition, pos: chunk.ChunkPosition,
size: i32, size: i32,
chunk: *chunk.Chunk, chunk: *chunk.Chunk,
lightingData: *[6]lighting.ChannelChunk, lightingData: [6]*lighting.ChannelChunk,
opaqueMesh: PrimitiveMesh, opaqueMesh: PrimitiveMesh,
transparentMesh: PrimitiveMesh, transparentMesh: PrimitiveMesh,
lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6, lastNeighborsSameLod: [6]?*const ChunkMesh = [_]?*const ChunkMesh{null} ** 6,
@ -444,20 +446,20 @@ pub const ChunkMesh = struct {
chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6, chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6,
pub fn init(self: *ChunkMesh, pos: chunk.ChunkPosition, ch: *chunk.Chunk) void { 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{ self.* = ChunkMesh{
.pos = pos, .pos = pos,
.size = chunk.chunkSize*pos.voxelSize, .size = chunk.chunkSize*pos.voxelSize,
.opaqueMesh = .{}, .opaqueMesh = .{},
.transparentMesh = .{}, .transparentMesh = .{},
.chunk = ch, .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); std.debug.assert(self.refCount.load(.Monotonic) == 0);
self.opaqueMesh.deinit(); self.opaqueMesh.deinit();
self.transparentMesh.deinit(); self.transparentMesh.deinit();
self.chunk.deinit();
main.globalAllocator.free(self.currentSorting); main.globalAllocator.free(self.currentSorting);
main.globalAllocator.free(self.sortingOutputBuffer); main.globalAllocator.free(self.sortingOutputBuffer);
main.globalAllocator.destroy(self.chunk); for(self.lightingData) |lightingChunk| {
main.globalAllocator.destroy(self.lightingData); lightingChunk.deinit();
}
} }
pub fn increaseRefCount(self: *ChunkMesh) void { pub fn increaseRefCount(self: *ChunkMesh) void {
@ -584,7 +588,7 @@ pub const ChunkMesh = struct {
} }
} }
self.mutex.unlock(); self.mutex.unlock();
for(self.lightingData[3..]) |*lightingData| { for(self.lightingData[3..]) |lightingData| {
lightingData.propagateLights(lightEmittingBlocks.items, true); lightingData.propagateLights(lightEmittingBlocks.items, true);
} }
sunLight: { 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); lightingData.propagateLights(sunStarters[0..index], true);
} }
} }
@ -728,11 +732,11 @@ pub const ChunkMesh = struct {
const oldBlock = self.chunk.blocks[chunk.getIndex(x, y, z)]; const oldBlock = self.chunk.blocks[chunk.getIndex(x, y, z)];
self.chunk.blocks[chunk.getIndex(x, y, z)] = newBlock; self.chunk.blocks[chunk.getIndex(x, y, z)] = newBlock;
self.mutex.unlock(); self.mutex.unlock();
for(self.lightingData[0..]) |*lightingData| { for(self.lightingData[0..]) |lightingData| {
lightingData.propagateLightsDestructive(&.{.{@intCast(x), @intCast(y), @intCast(z)}}); lightingData.propagateLightsDestructive(&.{.{@intCast(x), @intCast(y), @intCast(z)}});
} }
if(newBlock.light() != 0) { if(newBlock.light() != 0) {
for(self.lightingData[3..]) |*lightingData| { for(self.lightingData[3..]) |lightingData| {
lightingData.propagateLights(&.{.{@intCast(x), @intCast(y), @intCast(z)}}, false); lightingData.propagateLights(&.{.{@intCast(x), @intCast(y), @intCast(z)}}, false);
} }
} }

View File

@ -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 { pub const ChannelChunk = struct {
data: [chunk.chunkVolume]Atomic(u8), data: [chunk.chunkVolume]Atomic(u8),
mutex: std.Thread.Mutex, mutex: std.Thread.Mutex,
ch: *chunk.Chunk, ch: *chunk.Chunk,
channel: Channel, 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.mutex = .{};
self.ch = ch; self.ch = ch;
self.channel = channel; self.channel = channel;
@memset(&self.data, Atomic(u8).init(0)); @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 { const Entry = struct {
@ -235,7 +256,7 @@ pub const ChannelChunk = struct {
const otherZ = z+%chunk.Neighbors.relZ[neighbor] & chunk.chunkMask; 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; const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
defer neighborMesh.decreaseRefCount(); 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 index = chunk.getIndex(x, y, z);
const neighborIndex = chunk.getIndex(otherX, otherY, otherZ); const neighborIndex = chunk.getIndex(otherX, otherY, otherZ);
var value: u8 = neighborLightChunk.data[neighborIndex].load(.Unordered); var value: u8 = neighborLightChunk.data[neighborIndex].load(.Unordered);
@ -272,7 +293,7 @@ pub const ChannelChunk = struct {
defer if(mesh) |_mesh| _mesh.decreaseRefCount(); defer if(mesh) |_mesh| _mesh.decreaseRefCount();
var entryList = entries.entries; var entryList = entries.entries;
defer entryList.deinit(main.globalAllocator); 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| { for(entryList.items) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z); const index = chunk.getIndex(entry.x, entry.y, entry.z);
const value = channelChunk.data[index].load(.Unordered); const value = channelChunk.data[index].load(.Unordered);

View File

@ -1022,7 +1022,7 @@ pub const MeshGenerationTask = struct {
} }
pub fn clean(self: *MeshGenerationTask) void { pub fn clean(self: *MeshGenerationTask) void {
main.globalAllocator.destroy(self.mesh); self.mesh.deinit();
main.globalAllocator.destroy(self); main.globalAllocator.destroy(self);
} }
}; };

View File

@ -213,8 +213,7 @@ const ChunkManager = struct {
} }
fn chunkInitFunctionForCache(pos: ChunkPosition) *Chunk { fn chunkInitFunctionForCache(pos: ChunkPosition) *Chunk {
const ch = main.globalAllocator.create(Chunk); const ch = Chunk.init(pos);
ch.init(pos);
ch.generated = true; ch.generated = true;
// TODO: if(!ChunkIO.loadChunkFromFile(world, this)) { // TODO: if(!ChunkIO.loadChunkFromFile(world, this)) {
const caveMap = terrain.CaveMap.CaveMapView.init(ch); const caveMap = terrain.CaveMap.CaveMapView.init(ch);
@ -228,7 +227,7 @@ const ChunkManager = struct {
} }
fn chunkDeinitFunctionForCache(ch: *Chunk) void { fn chunkDeinitFunctionForCache(ch: *Chunk) void {
main.globalAllocator.destroy(ch); ch.deinit();
// TODO: Store chunk. // TODO: Store chunk.
} }
/// Generates a normal chunk at a given location, or if possible gets it from the cache. /// Generates a normal chunk at a given location, or if possible gets it from the cache.