Merge branch 'master' into 588-heightmap-derivative

This commit is contained in:
codemob-dev 2025-07-25 15:18:00 -04:00
commit b6008da38e
5 changed files with 26 additions and 50 deletions

View File

@ -1215,7 +1215,6 @@ pub const Protocols = struct {
var ligthMapReader = utils.BinaryReader.init(_inflatedData); var ligthMapReader = utils.BinaryReader.init(_inflatedData);
const map = main.globalAllocator.create(main.server.terrain.LightMap.LightMapFragment); const map = main.globalAllocator.create(main.server.terrain.LightMap.LightMapFragment);
map.init(pos.wx, pos.wy, pos.voxelSize); map.init(pos.wx, pos.wy, pos.voxelSize);
_ = map.refCount.fetchAdd(1, .monotonic);
for(&map.startHeight) |*val| { for(&map.startHeight) |*val| {
val.* = try ligthMapReader.readInt(i16); val.* = try ligthMapReader.readInt(i16);
} }

View File

@ -807,8 +807,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
var allSun: bool = self.chunk.data.paletteLength == 1 and self.chunk.data.palette[0].typ == 0; 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; var sunStarters: [chunk.chunkSize*chunk.chunkSize][3]u8 = undefined;
var index: usize = 0; var index: usize = 0;
const lightStartMap = mesh_storage.getLightMapPieceAndIncreaseRefCount(self.pos.wx, self.pos.wy, self.pos.voxelSize) orelse break :sunLight; const lightStartMap = mesh_storage.getLightMapPiece(self.pos.wx, self.pos.wy, self.pos.voxelSize) orelse break :sunLight;
defer lightStartMap.decreaseRefCount();
x = 0; x = 0;
while(x < chunk.chunkSize) : (x += 1) { while(x < chunk.chunkSize) : (x += 1) {
var y: u8 = 0; var y: u8 = 0;

View File

@ -33,7 +33,7 @@ const ChunkMeshNode = struct {
const storageSize = 64; const storageSize = 64;
const storageMask = storageSize - 1; const storageMask = storageSize - 1;
var storageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined; var storageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined;
var mapStorageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize]?*LightMap.LightMapFragment = undefined; var mapStorageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize]Atomic(?*LightMap.LightMapFragment) = undefined;
var meshList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator); var meshList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
var priorityMeshUpdateList: main.utils.ConcurrentQueue(chunk.ChunkPosition) = undefined; var priorityMeshUpdateList: main.utils.ConcurrentQueue(chunk.ChunkPosition) = undefined;
pub var updatableList = main.List(chunk.ChunkPosition).init(main.globalAllocator); pub var updatableList = main.List(chunk.ChunkPosition).init(main.globalAllocator);
@ -85,8 +85,8 @@ pub fn init() void { // MARK: init()
} }
} }
for(&mapStorageLists) |*mapStorageList| { for(&mapStorageLists) |*mapStorageList| {
mapStorageList.* = main.globalAllocator.create([storageSize*storageSize]?*LightMap.LightMapFragment); mapStorageList.* = main.globalAllocator.create([storageSize*storageSize]Atomic(?*LightMap.LightMapFragment));
@memset(mapStorageList.*, null); @memset(mapStorageList.*, .init(null));
} }
priorityMeshUpdateList = .init(main.globalAllocator, 16); priorityMeshUpdateList = .init(main.globalAllocator, 16);
mapUpdatableList = .init(main.globalAllocator, 16); mapUpdatableList = .init(main.globalAllocator, 16);
@ -102,7 +102,6 @@ pub fn deinit() void {
lastPz = 0; lastPz = 0;
lastRD = 0; lastRD = 0;
freeOldMeshes(olderPx, olderPy, olderPz, olderRD); freeOldMeshes(olderPx, olderPy, olderPz, olderRD);
main.heap.GarbageCollection.waitForFreeCompletion();
for(storageLists) |storageList| { for(storageLists) |storageList| {
main.globalAllocator.destroy(storageList); main.globalAllocator.destroy(storageList);
} }
@ -112,7 +111,7 @@ pub fn deinit() void {
updatableList.clearAndFree(); updatableList.clearAndFree();
while(mapUpdatableList.dequeue()) |map| { while(mapUpdatableList.dequeue()) |map| {
map.decreaseRefCount(); map.deferredDeinit();
} }
mapUpdatableList.deinit(); mapUpdatableList.deinit();
priorityMeshUpdateList.deinit(); priorityMeshUpdateList.deinit();
@ -121,6 +120,7 @@ pub fn deinit() void {
} }
blockUpdateList.deinit(); blockUpdateList.deinit();
meshList.clearAndFree(); meshList.clearAndFree();
main.heap.GarbageCollection.waitForFreeCompletion();
meshMemoryPool.deinit(); meshMemoryPool.deinit();
} }
@ -159,7 +159,7 @@ fn updateHigherLodNodeFinishedMeshing(pos_: chunk.ChunkPosition, finishedMeshing
} }
} }
fn getMapPiecePointer(x: i32, y: i32, voxelSize: u31) *?*LightMap.LightMapFragment { fn getMapPiecePointer(x: i32, y: i32, voxelSize: u31) *Atomic(?*LightMap.LightMapFragment) {
const lod = std.math.log2_int(u31, voxelSize); const lod = std.math.log2_int(u31, voxelSize);
var xIndex = x >> lod + LightMap.LightMapFragment.mapShift; var xIndex = x >> lod + LightMap.LightMapFragment.mapShift;
var yIndex = y >> lod + LightMap.LightMapFragment.mapShift; var yIndex = y >> lod + LightMap.LightMapFragment.mapShift;
@ -169,14 +169,8 @@ fn getMapPiecePointer(x: i32, y: i32, voxelSize: u31) *?*LightMap.LightMapFragme
return &(&mapStorageLists)[lod][@intCast(index)]; return &(&mapStorageLists)[lod][@intCast(index)];
} }
pub fn getLightMapPieceAndIncreaseRefCount(x: i32, y: i32, voxelSize: u31) ?*LightMap.LightMapFragment { pub fn getLightMapPiece(x: i32, y: i32, voxelSize: u31) ?*LightMap.LightMapFragment {
mutex.lock(); return getMapPiecePointer(x, y, voxelSize).load(.acquire);
defer mutex.unlock();
const result: *LightMap.LightMapFragment = getMapPiecePointer(x, y, voxelSize).* orelse {
return null;
};
result.increaseRefCount();
return result;
} }
pub fn getBlockFromRenderThread(x: i32, y: i32, z: i32) ?blocks.Block { pub fn getBlockFromRenderThread(x: i32, y: i32, z: i32) ?blocks.Block {
@ -437,13 +431,9 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16) void {
const yIndex = @divExact(y, size) & storageMask; const yIndex = @divExact(y, size) & storageMask;
const index = xIndex*storageSize + yIndex; const index = xIndex*storageSize + yIndex;
const mapPointer = &mapStorageLists[_lod][@intCast(index)]; const oldMap = mapStorageLists[_lod][@intCast(index)].swap(null, .monotonic);
mutex.lock();
const oldMap = mapPointer.*;
mapPointer.* = null;
mutex.unlock();
if(oldMap) |map| { if(oldMap) |map| {
map.decreaseRefCount(); map.deferredDeinit();
} }
} }
} }
@ -576,14 +566,12 @@ fn createNewMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16, meshR
const index = xIndex*storageSize + yIndex; const index = xIndex*storageSize + yIndex;
const pos = LightMap.MapFragmentPosition{.wx = x, .wy = y, .voxelSize = @as(u31, 1) << lod, .voxelSizeShift = lod}; const pos = LightMap.MapFragmentPosition{.wx = x, .wy = y, .voxelSize = @as(u31, 1) << lod, .voxelSizeShift = lod};
const node = &mapStorageLists[_lod][@intCast(index)]; const map = mapStorageLists[_lod][@intCast(index)].load(.unordered);
mutex.lock(); if(map) |_map| {
if(node.*) |map| { std.debug.assert(std.meta.eql(pos, _map.pos));
std.debug.assert(std.meta.eql(pos, map.pos));
} else { } else {
mapRequests.append(pos); mapRequests.append(pos);
} }
mutex.unlock();
} }
} }
} }
@ -770,13 +758,12 @@ pub fn updateMeshes(targetTime: i64) void { // MARK: updateMeshes()=
} }
while(mapUpdatableList.dequeue()) |map| { while(mapUpdatableList.dequeue()) |map| {
if(!isMapInRenderDistance(map.pos)) { if(!isMapInRenderDistance(map.pos)) {
map.decreaseRefCount(); map.deferredDeinit();
} else { } else {
const mapPointer = getMapPiecePointer(map.pos.wx, map.pos.wy, map.pos.voxelSize); const mapPointer = getMapPiecePointer(map.pos.wx, map.pos.wy, map.pos.voxelSize).swap(map, .release);
if(mapPointer.*) |old| { if(mapPointer) |old| {
old.decreaseRefCount(); old.deferredDeinit();
} }
mapPointer.* = map;
} }
} }
while(updatableList.items.len != 0) { while(updatableList.items.len != 0) {

View File

@ -20,25 +20,18 @@ pub const LightMapFragment = struct {
startHeight: [mapSize*mapSize]i16 = undefined, startHeight: [mapSize*mapSize]i16 = undefined,
pos: MapFragmentPosition, pos: MapFragmentPosition,
refCount: Atomic(u16) = .init(0),
pub fn init(self: *LightMapFragment, wx: i32, wy: i32, voxelSize: u31) void { pub fn init(self: *LightMapFragment, wx: i32, wy: i32, voxelSize: u31) void {
self.* = .{ self.* = .{
.pos = MapFragmentPosition.init(wx, wy, voxelSize), .pos = MapFragmentPosition.init(wx, wy, voxelSize),
}; };
} }
pub fn increaseRefCount(self: *LightMapFragment) void { fn deinit(self: *const LightMapFragment, _: usize) void {
const prevVal = self.refCount.fetchAdd(1, .monotonic); main.globalAllocator.destroy(self);
std.debug.assert(prevVal != 0);
} }
pub fn decreaseRefCount(self: *LightMapFragment) void { pub fn deferredDeinit(self: *LightMapFragment) void {
const prevVal = self.refCount.fetchSub(1, .monotonic); main.heap.GarbageCollection.deferredFree(.{.ptr = self, .freeFunction = main.utils.castFunctionSelfToAnyopaque(LightMapFragment.deinit)});
std.debug.assert(prevVal != 0);
if(prevVal == 1) {
main.globalAllocator.destroy(self);
}
} }
pub fn getHeight(self: *LightMapFragment, wx: i32, wy: i32) i32 { pub fn getHeight(self: *LightMapFragment, wx: i32, wy: i32) i32 {
@ -51,7 +44,7 @@ pub const LightMapFragment = struct {
const cacheSize = 1 << 6; // Must be a power of 2! const cacheSize = 1 << 6; // Must be a power of 2!
const cacheMask = cacheSize - 1; const cacheMask = cacheSize - 1;
const associativity = 8; // 64MiB MiB Cache size const associativity = 8; // 64MiB MiB Cache size
var cache: Cache(LightMapFragment, cacheSize, associativity, LightMapFragment.decreaseRefCount) = .{}; var cache: Cache(LightMapFragment, cacheSize, associativity, LightMapFragment.deferredDeinit) = .{};
fn cacheInit(pos: MapFragmentPosition) *LightMapFragment { fn cacheInit(pos: MapFragmentPosition) *LightMapFragment {
const mapFragment = main.globalAllocator.create(LightMapFragment); const mapFragment = main.globalAllocator.create(LightMapFragment);
@ -65,7 +58,6 @@ fn cacheInit(pos: MapFragmentPosition) *LightMapFragment {
mapFragment.startHeight[x << LightMapFragment.mapShift | y] = @max(0, baseHeight +| 16); // Simple heuristic. TODO: Update this value once chunks get generated in the region. mapFragment.startHeight[x << LightMapFragment.mapShift | y] = @max(0, baseHeight +| 16); // Simple heuristic. TODO: Update this value once chunks get generated in the region.
} }
} }
_ = @atomicRmw(u16, &mapFragment.refCount.raw, .Add, 1, .monotonic);
return mapFragment; return mapFragment;
} }
@ -73,12 +65,12 @@ pub fn deinit() void {
cache.clear(); cache.clear();
} }
pub fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, voxelSize: u31) *LightMapFragment { pub fn getOrGenerateFragment(wx: i32, wy: i32, voxelSize: u31) *LightMapFragment {
const compare = MapFragmentPosition.init( const compare = MapFragmentPosition.init(
wx & ~@as(i32, LightMapFragment.mapMask*voxelSize | voxelSize - 1), wx & ~@as(i32, LightMapFragment.mapMask*voxelSize | voxelSize - 1),
wy & ~@as(i32, LightMapFragment.mapMask*voxelSize | voxelSize - 1), wy & ~@as(i32, LightMapFragment.mapMask*voxelSize | voxelSize - 1),
voxelSize, voxelSize,
); );
const result = cache.findOrCreate(compare, cacheInit, LightMapFragment.increaseRefCount); const result = cache.findOrCreate(compare, cacheInit, null);
return result; return result;
} }

View File

@ -226,8 +226,7 @@ const ChunkManager = struct { // MARK: ChunkManager
pub fn run(self: *LightMapLoadTask) void { pub fn run(self: *LightMapLoadTask) void {
defer self.clean(); defer self.clean();
const map = terrain.LightMap.getOrGenerateFragmentAndIncreaseRefCount(self.pos.wx, self.pos.wy, self.pos.voxelSize); const map = terrain.LightMap.getOrGenerateFragment(self.pos.wx, self.pos.wy, self.pos.voxelSize);
defer map.decreaseRefCount();
if(self.source) |source| { if(self.source) |source| {
if(source.connected.load(.unordered)) main.network.Protocols.lightMapTransmission.sendLightMap(source.conn, map); if(source.connected.load(.unordered)) main.network.Protocols.lightMapTransmission.sendLightMap(source.conn, map);
} else { } else {