mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Audit usage of reference counting, making it thread safe in a (pretty rare) edge case.
Also uses a more consistent naming convention when reference counting is involved. Fixes #332 Potentially fixes #329 (I can't reproduce it anymore) Discovers #338
This commit is contained in:
parent
1a6454a92c
commit
3e0c666108
@ -72,7 +72,7 @@ fn findMusic(musicId: []const u8) ?[]f32 {
|
|||||||
{
|
{
|
||||||
taskMutex.lock();
|
taskMutex.lock();
|
||||||
defer taskMutex.unlock();
|
defer taskMutex.unlock();
|
||||||
if(musicCache.find(AudioData{.musicId = musicId})) |musicData| {
|
if(musicCache.find(AudioData{.musicId = musicId}, null)) |musicData| {
|
||||||
return musicData.data;
|
return musicData.data;
|
||||||
}
|
}
|
||||||
for(activeTasks.items) |taskFileName| {
|
for(activeTasks.items) |taskFileName| {
|
||||||
|
@ -669,7 +669,7 @@ pub const ItemDropRenderer = struct {
|
|||||||
|
|
||||||
fn getModelIndex(item: items.Item) u31 {
|
fn getModelIndex(item: items.Item) u31 {
|
||||||
const compareObject = ItemVoxelModel{.item = item};
|
const compareObject = ItemVoxelModel{.item = item};
|
||||||
return voxelModels.findOrCreate(compareObject, ItemVoxelModel.init).index;
|
return voxelModels.findOrCreate(compareObject, ItemVoxelModel.init, null).index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d, time: u32) void {
|
pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d, time: u32) void {
|
||||||
|
@ -243,7 +243,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
|||||||
|
|
||||||
worldFrameBuffer.bindTexture(c.GL_TEXTURE3);
|
worldFrameBuffer.bindTexture(c.GL_TEXTURE3);
|
||||||
|
|
||||||
const playerBlock = mesh_storage.getBlockFromAnyLodFromRenderThread(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2])));
|
const playerBlock = mesh_storage.getBlockFromAnyLod(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2])));
|
||||||
|
|
||||||
if(settings.bloom) {
|
if(settings.bloom) {
|
||||||
Bloom.render(lastWidth, lastHeight, playerBlock);
|
Bloom.render(lastWidth, lastHeight, playerBlock);
|
||||||
@ -695,7 +695,7 @@ pub const MeshSelection = struct {
|
|||||||
selectedBlockPos = null;
|
selectedBlockPos = null;
|
||||||
|
|
||||||
while(total_tMax < closestDistance) {
|
while(total_tMax < closestDistance) {
|
||||||
const block = mesh_storage.getBlockFromRenderThread(voxelPos[0], voxelPos[1], voxelPos[2]) orelse break;
|
const block = mesh_storage.getBlock(voxelPos[0], voxelPos[1], voxelPos[2]) orelse break;
|
||||||
if(block.typ != 0) {
|
if(block.typ != 0) {
|
||||||
if(block.blockClass() != .fluid) { // TODO: Buckets could select fluids
|
if(block.blockClass() != .fluid) { // TODO: Buckets could select fluids
|
||||||
const relativePlayerPos: Vec3f = @floatCast(pos - @as(Vec3d, @floatFromInt(voxelPos)));
|
const relativePlayerPos: Vec3f = @floatCast(pos - @as(Vec3d, @floatFromInt(voxelPos)));
|
||||||
@ -737,7 +737,7 @@ pub const MeshSelection = struct {
|
|||||||
|
|
||||||
pub fn placeBlock(inventoryStack: *main.items.ItemStack) void {
|
pub fn placeBlock(inventoryStack: *main.items.ItemStack) void {
|
||||||
if(selectedBlockPos) |selectedPos| {
|
if(selectedBlockPos) |selectedPos| {
|
||||||
var block = mesh_storage.getBlockFromRenderThread(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return;
|
var block = mesh_storage.getBlock(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return;
|
||||||
if(inventoryStack.item) |item| {
|
if(inventoryStack.item) |item| {
|
||||||
switch(item) {
|
switch(item) {
|
||||||
.baseItem => |baseItem| {
|
.baseItem => |baseItem| {
|
||||||
@ -758,7 +758,7 @@ pub const MeshSelection = struct {
|
|||||||
const neighborPos = posBeforeBlock;
|
const neighborPos = posBeforeBlock;
|
||||||
neighborDir = selectedPos - posBeforeBlock;
|
neighborDir = selectedPos - posBeforeBlock;
|
||||||
const relPos: Vec3f = @floatCast(lastPos - @as(Vec3d, @floatFromInt(neighborPos)));
|
const relPos: Vec3f = @floatCast(lastPos - @as(Vec3d, @floatFromInt(neighborPos)));
|
||||||
block = mesh_storage.getBlockFromRenderThread(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return;
|
block = mesh_storage.getBlock(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return;
|
||||||
if(block.typ == itemBlock) {
|
if(block.typ == itemBlock) {
|
||||||
if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, false)) {
|
if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, false)) {
|
||||||
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); (→ Sending it over the network)
|
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); (→ Sending it over the network)
|
||||||
@ -790,7 +790,7 @@ pub const MeshSelection = struct {
|
|||||||
|
|
||||||
pub fn breakBlock(inventoryStack: *main.items.ItemStack) void {
|
pub fn breakBlock(inventoryStack: *main.items.ItemStack) void {
|
||||||
if(selectedBlockPos) |selectedPos| {
|
if(selectedBlockPos) |selectedPos| {
|
||||||
var block = mesh_storage.getBlockFromRenderThread(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return;
|
var block = mesh_storage.getBlock(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return;
|
||||||
// TODO: Breaking animation and tools.
|
// TODO: Breaking animation and tools.
|
||||||
if(inventoryStack.item) |item| {
|
if(inventoryStack.item) |item| {
|
||||||
switch(item) {
|
switch(item) {
|
||||||
|
@ -22,7 +22,7 @@ const chunk_meshing = @import("chunk_meshing.zig");
|
|||||||
|
|
||||||
|
|
||||||
const ChunkMeshNode = struct {
|
const ChunkMeshNode = struct {
|
||||||
mesh: Atomic(?*chunk_meshing.ChunkMesh),
|
mesh: ?*chunk_meshing.ChunkMesh,
|
||||||
lod: u3,
|
lod: u3,
|
||||||
min: Vec2f,
|
min: Vec2f,
|
||||||
max: Vec2f,
|
max: Vec2f,
|
||||||
@ -32,7 +32,7 @@ const ChunkMeshNode = struct {
|
|||||||
const storageSize = 64;
|
const storageSize = 64;
|
||||||
const storageMask = storageSize - 1;
|
const storageMask = storageSize - 1;
|
||||||
var storageLists: [settings.highestLOD + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined;
|
var storageLists: [settings.highestLOD + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined;
|
||||||
var mapStorageLists: [settings.highestLOD + 1]*[storageSize*storageSize]Atomic(?*LightMap.LightMapFragment) = undefined;
|
var mapStorageLists: [settings.highestLOD + 1]*[storageSize*storageSize]?*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.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
|
var priorityMeshUpdateList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
|
||||||
pub var updatableList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
|
pub var updatableList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
|
||||||
@ -58,14 +58,14 @@ pub fn init() void {
|
|||||||
for(&storageLists) |*storageList| {
|
for(&storageLists) |*storageList| {
|
||||||
storageList.* = main.globalAllocator.create([storageSize*storageSize*storageSize]ChunkMeshNode);
|
storageList.* = main.globalAllocator.create([storageSize*storageSize*storageSize]ChunkMeshNode);
|
||||||
for(storageList.*) |*val| {
|
for(storageList.*) |*val| {
|
||||||
val.mesh = Atomic(?*chunk_meshing.ChunkMesh).init(null);
|
val.mesh = null;
|
||||||
val.rendered = false;
|
val.rendered = false;
|
||||||
val.active = false;
|
val.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(&mapStorageLists) |*mapStorageList| {
|
for(&mapStorageLists) |*mapStorageList| {
|
||||||
mapStorageList.* = main.globalAllocator.create([storageSize*storageSize]Atomic(?*LightMap.LightMapFragment));
|
mapStorageList.* = main.globalAllocator.create([storageSize*storageSize]?*LightMap.LightMapFragment);
|
||||||
@memset(mapStorageList.*, Atomic(?*LightMap.LightMapFragment).init(null));
|
@memset(mapStorageList.*, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ pub fn deinit() void {
|
|||||||
clearList.deinit();
|
clearList.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getNodeFromRenderThread(pos: chunk.ChunkPosition) *ChunkMeshNode {
|
fn getNodePointer(pos: chunk.ChunkPosition) *ChunkMeshNode {
|
||||||
const lod = std.math.log2_int(u31, pos.voxelSize);
|
const lod = std.math.log2_int(u31, pos.voxelSize);
|
||||||
var xIndex = pos.wx >> lod+chunk.chunkShift;
|
var xIndex = pos.wx >> lod+chunk.chunkShift;
|
||||||
var yIndex = pos.wy >> lod+chunk.chunkShift;
|
var yIndex = pos.wy >> lod+chunk.chunkShift;
|
||||||
@ -118,7 +118,7 @@ fn getNodeFromRenderThread(pos: chunk.ChunkPosition) *ChunkMeshNode {
|
|||||||
return &storageLists[lod][@intCast(index)];
|
return &storageLists[lod][@intCast(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getMapPieceLocation(x: i32, y: i32, voxelSize: u31) *Atomic(?*LightMap.LightMapFragment) {
|
fn getMapPiecePointer(x: i32, y: i32, voxelSize: u31) *?*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;
|
||||||
@ -129,62 +129,53 @@ fn getMapPieceLocation(x: i32, y: i32, voxelSize: u31) *Atomic(?*LightMap.LightM
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getLightMapPieceAndIncreaseRefCount(x: i32, y: i32, voxelSize: u31) ?*LightMap.LightMapFragment {
|
pub fn getLightMapPieceAndIncreaseRefCount(x: i32, y: i32, voxelSize: u31) ?*LightMap.LightMapFragment {
|
||||||
const result: *LightMap.LightMapFragment = getMapPieceLocation(x, y, voxelSize).load(.acquire) orelse return null;
|
mutex.lock();
|
||||||
var refCount: u16 = 1;
|
defer mutex.unlock();
|
||||||
while(result.refCount.cmpxchgWeak(refCount, refCount+1, .monotonic, .monotonic)) |otherVal| {
|
const result: *LightMap.LightMapFragment = getMapPiecePointer(x, y, voxelSize).* orelse {
|
||||||
if(otherVal == 0) return null;
|
return null;
|
||||||
refCount = otherVal;
|
};
|
||||||
}
|
result.increaseRefCount();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBlockFromRenderThread(x: i32, y: i32, z: i32) ?blocks.Block {
|
pub fn getBlock(x: i32, y: i32, z: i32) ?blocks.Block {
|
||||||
const node = getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=1});
|
const node = getNodePointer(.{.wx = x, .wy = y, .wz = z, .voxelSize=1});
|
||||||
const mesh = node.mesh.load(.acquire) orelse return null;
|
mutex.lock();
|
||||||
|
defer mutex.unlock();
|
||||||
|
const mesh = node.mesh orelse return null;
|
||||||
const block = mesh.chunk.getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
|
const block = mesh.chunk.getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBlockFromAnyLodFromRenderThread(x: i32, y: i32, z: i32) blocks.Block {
|
pub fn getBlockFromAnyLod(x: i32, y: i32, z: i32) blocks.Block {
|
||||||
var lod: u5 = 0;
|
var lod: u5 = 0;
|
||||||
while(lod < settings.highestLOD) : (lod += 1) {
|
while(lod < settings.highestLOD) : (lod += 1) {
|
||||||
const node = getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod});
|
const node = getNodePointer(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod});
|
||||||
const mesh = node.mesh.load(.acquire) orelse continue;
|
mutex.lock();
|
||||||
|
defer mutex.unlock();
|
||||||
|
const mesh = node.mesh orelse continue;
|
||||||
const block = mesh.chunk.getBlock(x & chunk.chunkMask<<lod, y & chunk.chunkMask<<lod, z & chunk.chunkMask<<lod);
|
const block = mesh.chunk.getBlock(x & chunk.chunkMask<<lod, y & chunk.chunkMask<<lod, z & chunk.chunkMask<<lod);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
return blocks.Block{.typ = 0, .data = 0};
|
return blocks.Block{.typ = 0, .data = 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMeshFromAnyLodFromRenderThread(wx: i32, wy: i32, wz: i32, voxelSize: u31) ?*chunk_meshing.ChunkMesh {
|
|
||||||
var lod: u5 = @ctz(voxelSize);
|
|
||||||
while(lod < settings.highestLOD) : (lod += 1) {
|
|
||||||
const node = getNodeFromRenderThread(.{.wx = wx & ~chunk.chunkMask<<lod, .wy = wy & ~chunk.chunkMask<<lod, .wz = wz & ~chunk.chunkMask<<lod, .voxelSize=@as(u31, 1) << lod});
|
|
||||||
return node.mesh.load(.acquire) orelse continue;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getNeighborFromRenderThread(_pos: chunk.ChunkPosition, resolution: u31, neighbor: u3) ?*chunk_meshing.ChunkMesh {
|
|
||||||
var pos = _pos;
|
|
||||||
pos.wx +%= pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relX[neighbor];
|
|
||||||
pos.wy +%= pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relY[neighbor];
|
|
||||||
pos.wz +%= pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relZ[neighbor];
|
|
||||||
pos.voxelSize = resolution;
|
|
||||||
const node = getNodeFromRenderThread(pos);
|
|
||||||
return node.mesh.load(.acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getMeshAndIncreaseRefCount(pos: chunk.ChunkPosition) ?*chunk_meshing.ChunkMesh {
|
pub fn getMeshAndIncreaseRefCount(pos: chunk.ChunkPosition) ?*chunk_meshing.ChunkMesh {
|
||||||
const node = getNodeFromRenderThread(pos);
|
|
||||||
const mesh = node.mesh.load(.acquire) orelse return null;
|
|
||||||
const lod = std.math.log2_int(u31, pos.voxelSize);
|
const lod = std.math.log2_int(u31, pos.voxelSize);
|
||||||
const mask = ~((@as(i32, 1) << lod+chunk.chunkShift) - 1);
|
const mask = ~((@as(i32, 1) << lod+chunk.chunkShift) - 1);
|
||||||
if(pos.wx & mask != mesh.pos.wx or pos.wy & mask != mesh.pos.wy or pos.wz & mask != mesh.pos.wz) return null;
|
const node = getNodePointer(pos);
|
||||||
if(mesh.tryIncreaseRefCount()) {
|
mutex.lock();
|
||||||
return mesh;
|
const mesh = node.mesh orelse {
|
||||||
|
mutex.unlock();
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
mesh.increaseRefCount();
|
||||||
|
mutex.unlock();
|
||||||
|
if(pos.wx & mask != mesh.pos.wx or pos.wy & mask != mesh.pos.wy or pos.wz & mask != mesh.pos.wz) {
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMeshFromAnyLodAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) ?*chunk_meshing.ChunkMesh {
|
pub fn getMeshFromAnyLodAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) ?*chunk_meshing.ChunkMesh {
|
||||||
@ -327,9 +318,12 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: i32) void {
|
|||||||
const index = (xIndex*storageSize + yIndex)*storageSize + zIndex;
|
const index = (xIndex*storageSize + yIndex)*storageSize + zIndex;
|
||||||
|
|
||||||
const node = &storageLists[_lod][@intCast(index)];
|
const node = &storageLists[_lod][@intCast(index)];
|
||||||
if(node.mesh.load(.acquire)) |mesh| {
|
mutex.lock();
|
||||||
|
const oldMesh = node.mesh;
|
||||||
|
node.mesh = null;
|
||||||
|
mutex.unlock();
|
||||||
|
if(oldMesh) |mesh| {
|
||||||
mesh.decreaseRefCount();
|
mesh.decreaseRefCount();
|
||||||
node.mesh.store(null, .release);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,9 +379,12 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: i32) void {
|
|||||||
const yIndex = @divExact(y, size) & storageMask;
|
const yIndex = @divExact(y, size) & storageMask;
|
||||||
const index = xIndex*storageSize + yIndex;
|
const index = xIndex*storageSize + yIndex;
|
||||||
|
|
||||||
const mapAtomic = &mapStorageLists[_lod][@intCast(index)];
|
const mapPointer = &mapStorageLists[_lod][@intCast(index)];
|
||||||
if(mapAtomic.load(.acquire)) |map| {
|
mutex.lock();
|
||||||
mapAtomic.store(null, .release);
|
const oldMap = mapPointer.*;
|
||||||
|
mapPointer.* = null;
|
||||||
|
mutex.unlock();
|
||||||
|
if(oldMap) |map| {
|
||||||
map.decreaseRefCount();
|
map.decreaseRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,11 +457,13 @@ fn createNewMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: i32, meshR
|
|||||||
const pos = chunk.ChunkPosition{.wx=x, .wy=y, .wz=z, .voxelSize=@as(u31, 1)<<lod};
|
const pos = chunk.ChunkPosition{.wx=x, .wy=y, .wz=z, .voxelSize=@as(u31, 1)<<lod};
|
||||||
|
|
||||||
const node = &storageLists[_lod][@intCast(index)];
|
const node = &storageLists[_lod][@intCast(index)];
|
||||||
if(node.mesh.load(.acquire)) |mesh| {
|
mutex.lock();
|
||||||
|
if(node.mesh) |mesh| {
|
||||||
std.debug.assert(std.meta.eql(pos, mesh.pos));
|
std.debug.assert(std.meta.eql(pos, mesh.pos));
|
||||||
} else {
|
} else {
|
||||||
meshRequests.append(pos);
|
meshRequests.append(pos);
|
||||||
}
|
}
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,11 +520,13 @@ fn createNewMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: i32, meshR
|
|||||||
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 node = &mapStorageLists[_lod][@intCast(index)];
|
||||||
if(node.load(.acquire)) |map| {
|
mutex.lock();
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -588,8 +589,11 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
firstPos.wz &= ~@as(i32, chunk.chunkMask);
|
firstPos.wz &= ~@as(i32, chunk.chunkMask);
|
||||||
var lod: u3 = 0;
|
var lod: u3 = 0;
|
||||||
while(lod <= settings.highestLOD) : (lod += 1) {
|
while(lod <= settings.highestLOD) : (lod += 1) {
|
||||||
const node = getNodeFromRenderThread(firstPos);
|
const node = getNodePointer(firstPos);
|
||||||
if(node.mesh.load(.acquire) != null and node.mesh.load(.acquire).?.finishedMeshing) {
|
mutex.lock();
|
||||||
|
const hasMesh = node.mesh != null and node.mesh.?.finishedMeshing;
|
||||||
|
mutex.unlock();
|
||||||
|
if(hasMesh) {
|
||||||
node.lod = lod;
|
node.lod = lod;
|
||||||
node.min = @splat(-1);
|
node.min = @splat(-1);
|
||||||
node.max = @splat(1);
|
node.max = @splat(1);
|
||||||
@ -613,8 +617,20 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
while(searchList.removeOrNull()) |data| {
|
while(searchList.removeOrNull()) |data| {
|
||||||
nodeList.append(data.node);
|
nodeList.append(data.node);
|
||||||
data.node.active = false;
|
data.node.active = false;
|
||||||
const mesh = data.node.mesh.load(.acquire).?;
|
|
||||||
std.debug.assert(mesh.finishedMeshing);
|
mutex.lock();
|
||||||
|
const mesh = data.node.mesh orelse {
|
||||||
|
mutex.unlock();
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if(!mesh.finishedMeshing) {
|
||||||
|
mutex.unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mesh.increaseRefCount();
|
||||||
|
defer mesh.decreaseRefCount();
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
mesh.visibilityMask = 0xff;
|
mesh.visibilityMask = 0xff;
|
||||||
const relPos: Vec3d = @as(Vec3d, @floatFromInt(Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz})) - playerPos;
|
const relPos: Vec3d = @as(Vec3d, @floatFromInt(Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz})) - playerPos;
|
||||||
const relPosFloat: Vec3f = @floatCast(relPos);
|
const relPosFloat: Vec3f = @floatCast(relPos);
|
||||||
@ -770,8 +786,10 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
neighborPos.wz &= ~@as(i32, neighborPos.voxelSize*chunk.chunkSize);
|
neighborPos.wz &= ~@as(i32, neighborPos.voxelSize*chunk.chunkSize);
|
||||||
neighborPos.voxelSize *= 2;
|
neighborPos.voxelSize *= 2;
|
||||||
}
|
}
|
||||||
const node = getNodeFromRenderThread(neighborPos);
|
const node = getNodePointer(neighborPos);
|
||||||
if(node.mesh.load(.acquire)) |neighborMesh| {
|
if(getMeshAndIncreaseRefCount(neighborPos)) |neighborMesh| {
|
||||||
|
std.debug.assert(std.meta.eql(neighborPos, neighborMesh.pos));
|
||||||
|
defer neighborMesh.decreaseRefCount();
|
||||||
if(!neighborMesh.finishedMeshing) continue;
|
if(!neighborMesh.finishedMeshing) continue;
|
||||||
// Ensure that there are no high-to-low lod transitions, which would produce cracks.
|
// Ensure that there are no high-to-low lod transitions, which would produce cracks.
|
||||||
if(lod == data.node.lod and lod != settings.highestLOD and !node.rendered) {
|
if(lod == data.node.lod and lod != settings.highestLOD and !node.rendered) {
|
||||||
@ -788,7 +806,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
.wz = neighborPos.wz + chunk.Neighbors.relZ[neighbor2]*chunk.chunkSize*neighborPos.voxelSize,
|
.wz = neighborPos.wz + chunk.Neighbors.relZ[neighbor2]*chunk.chunkSize*neighborPos.voxelSize,
|
||||||
.voxelSize = neighborPos.voxelSize,
|
.voxelSize = neighborPos.voxelSize,
|
||||||
};
|
};
|
||||||
const node2 = getNodeFromRenderThread(neighborPos2);
|
const node2 = getNodePointer(neighborPos2);
|
||||||
if(node2.rendered) {
|
if(node2.rendered) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -800,7 +818,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
.wz = neighborPos.wz + chunk.Neighbors.relZ[neighbor2]*chunk.chunkSize*neighborPos.voxelSize,
|
.wz = neighborPos.wz + chunk.Neighbors.relZ[neighbor2]*chunk.chunkSize*neighborPos.voxelSize,
|
||||||
.voxelSize = neighborPos.voxelSize << 1,
|
.voxelSize = neighborPos.voxelSize << 1,
|
||||||
};
|
};
|
||||||
const node2 = getNodeFromRenderThread(neighborPos2);
|
const node2 = getNodePointer(neighborPos2);
|
||||||
if(node2.rendered) {
|
if(node2.rendered) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
break;
|
break;
|
||||||
@ -837,10 +855,25 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
|
|||||||
}
|
}
|
||||||
for(nodeList.items) |node| {
|
for(nodeList.items) |node| {
|
||||||
node.rendered = false;
|
node.rendered = false;
|
||||||
const mesh = node.mesh.load(.acquire).?;
|
|
||||||
|
mutex.lock();
|
||||||
|
const mesh = node.mesh orelse {
|
||||||
|
mutex.unlock();
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if(!mesh.finishedMeshing) {
|
||||||
|
mutex.unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mesh.increaseRefCount();
|
||||||
|
defer mesh.decreaseRefCount();
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
if(mesh.pos.voxelSize != @as(u31, 1) << settings.highestLOD) {
|
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});
|
const parent = getNodePointer(.{.wx=mesh.pos.wx, .wy=mesh.pos.wy, .wz=mesh.pos.wz, .voxelSize=mesh.pos.voxelSize << 1});
|
||||||
if(parent.mesh.load(.acquire)) |parentMesh| {
|
mutex.lock();
|
||||||
|
defer mutex.unlock();
|
||||||
|
if(parent.mesh) |parentMesh| {
|
||||||
const sizeShift = chunk.chunkShift + @ctz(mesh.pos.voxelSize);
|
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);
|
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);
|
parentMesh.visibilityMask &= ~(@as(u8, 1) << octantIndex);
|
||||||
@ -867,8 +900,8 @@ pub fn updateMeshes(targetTime: i64) void {
|
|||||||
defer blockUpdateMutex.unlock();
|
defer blockUpdateMutex.unlock();
|
||||||
for(blockUpdateList.items) |blockUpdate| {
|
for(blockUpdateList.items) |blockUpdate| {
|
||||||
const pos = chunk.ChunkPosition{.wx=blockUpdate.x, .wy=blockUpdate.y, .wz=blockUpdate.z, .voxelSize=1};
|
const pos = chunk.ChunkPosition{.wx=blockUpdate.x, .wy=blockUpdate.y, .wz=blockUpdate.z, .voxelSize=1};
|
||||||
const node = getNodeFromRenderThread(pos);
|
if(getMeshAndIncreaseRefCount(pos)) |mesh| {
|
||||||
if(node.mesh.load(.acquire)) |mesh| {
|
defer mesh.decreaseRefCount();
|
||||||
mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock);
|
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.
|
} // TODO: It seems like we simply ignore the block update if we don't have the mesh yet.
|
||||||
}
|
}
|
||||||
@ -890,10 +923,14 @@ pub fn updateMeshes(targetTime: i64) void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mesh.needsMeshUpdate = false;
|
mesh.needsMeshUpdate = false;
|
||||||
|
if(getNodePointer(mesh.pos).mesh != mesh) {
|
||||||
|
mutex.unlock();
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
defer mutex.lock();
|
defer mutex.lock();
|
||||||
mesh.decreaseRefCount();
|
mesh.decreaseRefCount();
|
||||||
if(getNodeFromRenderThread(mesh.pos).mesh.load(.acquire) != mesh) continue; // This mesh isn't used for rendering anymore.
|
|
||||||
mesh.uploadData();
|
mesh.uploadData();
|
||||||
if(std.time.milliTimestamp() >= targetTime) break; // Update at least one mesh.
|
if(std.time.milliTimestamp() >= targetTime) break; // Update at least one mesh.
|
||||||
}
|
}
|
||||||
@ -901,9 +938,11 @@ pub fn updateMeshes(targetTime: i64) void {
|
|||||||
if(!isMapInRenderDistance(map.pos)) {
|
if(!isMapInRenderDistance(map.pos)) {
|
||||||
map.decreaseRefCount();
|
map.decreaseRefCount();
|
||||||
} else {
|
} else {
|
||||||
if(getMapPieceLocation(map.pos.wx, map.pos.wy, map.pos.voxelSize).swap(map, .acq_rel)) |old| {
|
const mapPointer = getMapPiecePointer(map.pos.wx, map.pos.wy, map.pos.voxelSize);
|
||||||
|
if(mapPointer.*) |old| {
|
||||||
old.decreaseRefCount();
|
old.decreaseRefCount();
|
||||||
}
|
}
|
||||||
|
mapPointer.* = map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(updatableList.items.len != 0) {
|
while(updatableList.items.len != 0) {
|
||||||
@ -935,11 +974,15 @@ pub fn updateMeshes(targetTime: i64) void {
|
|||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
defer mutex.lock();
|
defer mutex.lock();
|
||||||
if(isInRenderDistance(mesh.pos)) {
|
if(isInRenderDistance(mesh.pos)) {
|
||||||
const node = getNodeFromRenderThread(mesh.pos);
|
const node = getNodePointer(mesh.pos);
|
||||||
mesh.finishedMeshing = true;
|
mesh.finishedMeshing = true;
|
||||||
mesh.uploadData();
|
mesh.uploadData();
|
||||||
if(node.mesh.swap(mesh, .acq_rel)) |oldMesh| {
|
mutex.lock();
|
||||||
oldMesh.decreaseRefCount();
|
const oldMesh = node.mesh;
|
||||||
|
node.mesh = mesh;
|
||||||
|
mutex.unlock();
|
||||||
|
if(oldMesh) |_oldMesh| {
|
||||||
|
_oldMesh.decreaseRefCount();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mesh.decreaseRefCount();
|
mesh.decreaseRefCount();
|
||||||
@ -973,12 +1016,12 @@ pub fn addMeshToStorage(mesh: *chunk_meshing.ChunkMesh) error{AlreadyStored}!voi
|
|||||||
mutex.lock();
|
mutex.lock();
|
||||||
defer mutex.unlock();
|
defer mutex.unlock();
|
||||||
if(isInRenderDistance(mesh.pos)) {
|
if(isInRenderDistance(mesh.pos)) {
|
||||||
const node = getNodeFromRenderThread(mesh.pos);
|
const node = getNodePointer(mesh.pos);
|
||||||
if(node.mesh.cmpxchgStrong(null, mesh, .acq_rel, .monotonic) != null) {
|
if(node.mesh != null) {
|
||||||
return error.AlreadyStored;
|
return error.AlreadyStored;
|
||||||
} else {
|
|
||||||
mesh.increaseRefCount();
|
|
||||||
}
|
}
|
||||||
|
node.mesh = mesh;
|
||||||
|
mesh.increaseRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,19 @@ pub const CaveBiomeMapFragment = struct {
|
|||||||
relZ >>= caveBiomeShift;
|
relZ >>= caveBiomeShift;
|
||||||
return relX << 2*(caveBiomeMapShift - caveBiomeShift) | relY << caveBiomeMapShift-caveBiomeShift | relZ;
|
return relX << 2*(caveBiomeMapShift - caveBiomeShift) | relY << caveBiomeMapShift-caveBiomeShift | relZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increaseRefCount(self: *CaveBiomeMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decreaseRefCount(self: *CaveBiomeMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
|
main.globalAllocator.destroy(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A generator for the cave biome map.
|
/// A generator for the cave biome map.
|
||||||
@ -105,20 +118,20 @@ pub const InterpolatableCaveBiomeMapView = struct {
|
|||||||
pub fn init(pos: ChunkPosition, width: i32) InterpolatableCaveBiomeMapView {
|
pub fn init(pos: ChunkPosition, width: i32) InterpolatableCaveBiomeMapView {
|
||||||
return InterpolatableCaveBiomeMapView {
|
return InterpolatableCaveBiomeMapView {
|
||||||
.fragments = [_]*CaveBiomeMapFragment {
|
.fragments = [_]*CaveBiomeMapFragment {
|
||||||
getOrGenerateFragment(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy -% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz -% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
getOrGenerateFragment(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wy +% CaveBiomeMapFragment.caveBiomeMapSize/2, pos.wz +% CaveBiomeMapFragment.caveBiomeMapSize/2),
|
||||||
},
|
},
|
||||||
.surfaceFragments = [_]*MapFragment {
|
.surfaceFragments = [_]*MapFragment {
|
||||||
SurfaceMap.getOrGenerateFragment(pos.wx -% 32, pos.wy -% 32, pos.voxelSize),
|
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% 32, pos.wy -% 32, pos.voxelSize),
|
||||||
SurfaceMap.getOrGenerateFragment(pos.wx -% 32, pos.wy +% width +% 32, pos.voxelSize),
|
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx -% 32, pos.wy +% width +% 32, pos.voxelSize),
|
||||||
SurfaceMap.getOrGenerateFragment(pos.wx +% width +% 32, pos.wy -% 32, pos.voxelSize),
|
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width +% 32, pos.wy -% 32, pos.voxelSize),
|
||||||
SurfaceMap.getOrGenerateFragment(pos.wx +% width +% 32, pos.wy +% width +% 32, pos.voxelSize),
|
SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx +% width +% 32, pos.wy +% width +% 32, pos.voxelSize),
|
||||||
},
|
},
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.width = width,
|
.width = width,
|
||||||
@ -127,10 +140,10 @@ pub const InterpolatableCaveBiomeMapView = struct {
|
|||||||
|
|
||||||
pub fn deinit(self: InterpolatableCaveBiomeMapView) void {
|
pub fn deinit(self: InterpolatableCaveBiomeMapView) void {
|
||||||
for(self.fragments) |mapFragment| {
|
for(self.fragments) |mapFragment| {
|
||||||
mapFragmentDeinit(mapFragment);
|
mapFragment.decreaseRefCount();
|
||||||
}
|
}
|
||||||
for(self.surfaceFragments) |mapFragment| {
|
for(self.surfaceFragments) |mapFragment| {
|
||||||
mapFragment.deinit();
|
mapFragment.decreaseRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +447,7 @@ pub const CaveBiomeMapView = struct {
|
|||||||
const cacheSize = 1 << 8; // Must be a power of 2!
|
const cacheSize = 1 << 8; // Must be a power of 2!
|
||||||
const cacheMask = cacheSize - 1;
|
const cacheMask = cacheSize - 1;
|
||||||
const associativity = 8;
|
const associativity = 8;
|
||||||
var cache: Cache(CaveBiomeMapFragment, cacheSize, associativity, mapFragmentDeinit) = .{};
|
var cache: Cache(CaveBiomeMapFragment, cacheSize, associativity, CaveBiomeMapFragment.decreaseRefCount) = .{};
|
||||||
|
|
||||||
var profile: TerrainGenerationProfile = undefined;
|
var profile: TerrainGenerationProfile = undefined;
|
||||||
|
|
||||||
@ -457,12 +470,6 @@ pub fn deinit() void {
|
|||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapFragmentDeinit(mapFragment: *CaveBiomeMapFragment) void {
|
|
||||||
if(@atomicRmw(u16, &mapFragment.refCount.raw, .Sub, 1, .monotonic) == 1) {
|
|
||||||
main.globalAllocator.destroy(mapFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cacheInit(pos: ChunkPosition) *CaveBiomeMapFragment {
|
fn cacheInit(pos: ChunkPosition) *CaveBiomeMapFragment {
|
||||||
const mapFragment = main.globalAllocator.create(CaveBiomeMapFragment);
|
const mapFragment = main.globalAllocator.create(CaveBiomeMapFragment);
|
||||||
mapFragment.init(pos.wx, pos.wy, pos.wz);
|
mapFragment.init(pos.wx, pos.wy, pos.wz);
|
||||||
@ -473,7 +480,7 @@ fn cacheInit(pos: ChunkPosition) *CaveBiomeMapFragment {
|
|||||||
return mapFragment;
|
return mapFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getOrGenerateFragment(_wx: i32, _wy: i32, _wz: i32) *CaveBiomeMapFragment {
|
fn getOrGenerateFragmentAndIncreaseRefCount(_wx: i32, _wy: i32, _wz: i32) *CaveBiomeMapFragment {
|
||||||
const wx = _wx & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
const wx = _wx & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
||||||
const wy = _wy & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
const wy = _wy & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
||||||
const wz = _wz & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
const wz = _wz & ~@as(i32, CaveBiomeMapFragment.caveBiomeMapMask);
|
||||||
@ -481,7 +488,6 @@ fn getOrGenerateFragment(_wx: i32, _wy: i32, _wz: i32) *CaveBiomeMapFragment {
|
|||||||
.wx = wx, .wy = wy, .wz = wz,
|
.wx = wx, .wy = wy, .wz = wz,
|
||||||
.voxelSize = CaveBiomeMapFragment.caveBiomeSize,
|
.voxelSize = CaveBiomeMapFragment.caveBiomeSize,
|
||||||
};
|
};
|
||||||
const result = cache.findOrCreate(compare, cacheInit);
|
const result = cache.findOrCreate(compare, cacheInit, CaveBiomeMapFragment.increaseRefCount);
|
||||||
std.debug.assert(@atomicRmw(u16, &result.refCount.raw, .Add, 1, .monotonic) != 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
@ -61,6 +61,19 @@ pub const CaveMapFragment = struct {
|
|||||||
return maskLower | maskUpper;
|
return maskLower | maskUpper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increaseRefCount(self: *CaveMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decreaseRefCount(self: *CaveMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
|
main.globalAllocator.destroy(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addRange(self: *CaveMapFragment, _relX: i32, _relY: i32, _start: i32, _end: i32) void {
|
pub fn addRange(self: *CaveMapFragment, _relX: i32, _relY: i32, _start: i32, _end: i32) void {
|
||||||
const relX = _relX >> self.voxelShift;
|
const relX = _relX >> self.voxelShift;
|
||||||
const relY = _relY >> self.voxelShift;
|
const relY = _relY >> self.voxelShift;
|
||||||
@ -135,21 +148,21 @@ pub const CaveMapView = struct {
|
|||||||
return CaveMapView {
|
return CaveMapView {
|
||||||
.reference = chunk,
|
.reference = chunk,
|
||||||
.fragments = [_]*CaveMapFragment {
|
.fragments = [_]*CaveMapFragment {
|
||||||
getOrGenerateFragment(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx -% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy -% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz -% chunk.width, chunk.pos.voxelSize),
|
||||||
getOrGenerateFragment(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
getOrGenerateFragmentAndIncreaseRefCount(chunk.pos.wx +% chunk.width, chunk.pos.wy +% chunk.width, chunk.pos.wz +% chunk.width, chunk.pos.voxelSize),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: CaveMapView) void {
|
pub fn deinit(self: CaveMapView) void {
|
||||||
for(self.fragments) |mapFragment| {
|
for(self.fragments) |mapFragment| {
|
||||||
mapFragmentDeinit(mapFragment);
|
mapFragment.decreaseRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,15 +298,9 @@ pub const CaveMapView = struct {
|
|||||||
const cacheSize = 1 << 9; // Must be a power of 2!
|
const cacheSize = 1 << 9; // Must be a power of 2!
|
||||||
const cacheMask = cacheSize - 1;
|
const cacheMask = cacheSize - 1;
|
||||||
const associativity = 8; // 512 MiB Cache size
|
const associativity = 8; // 512 MiB Cache size
|
||||||
var cache: Cache(CaveMapFragment, cacheSize, associativity, mapFragmentDeinit) = .{};
|
var cache: Cache(CaveMapFragment, cacheSize, associativity, CaveMapFragment.decreaseRefCount) = .{};
|
||||||
var profile: TerrainGenerationProfile = undefined;
|
var profile: TerrainGenerationProfile = undefined;
|
||||||
|
|
||||||
fn mapFragmentDeinit(mapFragment: *CaveMapFragment) void {
|
|
||||||
if(@atomicRmw(u16, &mapFragment.refCount.raw, .Sub, 1, .monotonic) == 1) {
|
|
||||||
main.globalAllocator.destroy(mapFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cacheInit(pos: ChunkPosition) *CaveMapFragment {
|
fn cacheInit(pos: ChunkPosition) *CaveMapFragment {
|
||||||
const mapFragment = main.globalAllocator.create(CaveMapFragment);
|
const mapFragment = main.globalAllocator.create(CaveMapFragment);
|
||||||
mapFragment.init(pos.wx, pos.wy, pos.wz, pos.voxelSize);
|
mapFragment.init(pos.wx, pos.wy, pos.wz, pos.voxelSize);
|
||||||
@ -323,14 +330,13 @@ pub fn deinit() void {
|
|||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getOrGenerateFragment(wx: i32, wy: i32, wz: i32, voxelSize: u31) *CaveMapFragment {
|
fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) *CaveMapFragment {
|
||||||
const compare = ChunkPosition {
|
const compare = ChunkPosition {
|
||||||
.wx = wx & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize-1),
|
.wx = wx & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize-1),
|
||||||
.wy = wy & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize-1),
|
.wy = wy & ~@as(i32, CaveMapFragment.widthMask*voxelSize | voxelSize-1),
|
||||||
.wz = wz & ~@as(i32, CaveMapFragment.heightMask*voxelSize | voxelSize-1),
|
.wz = wz & ~@as(i32, CaveMapFragment.heightMask*voxelSize | voxelSize-1),
|
||||||
.voxelSize = voxelSize,
|
.voxelSize = voxelSize,
|
||||||
};
|
};
|
||||||
const result = cache.findOrCreate(compare, cacheInit);
|
const result = cache.findOrCreate(compare, cacheInit, CaveMapFragment.increaseRefCount);
|
||||||
std.debug.assert(@atomicRmw(u16, &result.refCount.raw, .Add, 1, .monotonic) != 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
@ -60,6 +60,19 @@ pub const ClimateMapFragment = struct {
|
|||||||
pub fn hashCode(wx: i32, wy: i32) u32 {
|
pub fn hashCode(wx: i32, wy: i32) u32 {
|
||||||
return @bitCast((wx >> mapShift)*%33 + (wy >> mapShift));
|
return @bitCast((wx >> mapShift)*%33 + (wy >> mapShift));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increaseRefCount(self: *ClimateMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decreaseRefCount(self: *ClimateMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
|
main.globalAllocator.destroy(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Generates the climate(aka Biome) map, which is a rough representation of the world.
|
/// Generates the climate(aka Biome) map, which is a rough representation of the world.
|
||||||
@ -91,7 +104,7 @@ pub const ClimateMapGenerator = struct {
|
|||||||
const cacheSize = 1 << 8; // Must be a power of 2!
|
const cacheSize = 1 << 8; // Must be a power of 2!
|
||||||
const cacheMask = cacheSize - 1;
|
const cacheMask = cacheSize - 1;
|
||||||
const associativity = 4;
|
const associativity = 4;
|
||||||
var cache: Cache(ClimateMapFragment, cacheSize, associativity, mapFragmentDeinit) = .{};
|
var cache: Cache(ClimateMapFragment, cacheSize, associativity, ClimateMapFragment.decreaseRefCount) = .{};
|
||||||
var profile: TerrainGenerationProfile = undefined;
|
var profile: TerrainGenerationProfile = undefined;
|
||||||
|
|
||||||
pub fn initGenerators() void {
|
pub fn initGenerators() void {
|
||||||
@ -105,12 +118,6 @@ pub fn deinitGenerators() void {
|
|||||||
ClimateMapGenerator.generatorRegistry.clearAndFree(main.globalAllocator.allocator);
|
ClimateMapGenerator.generatorRegistry.clearAndFree(main.globalAllocator.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapFragmentDeinit(mapFragment: *ClimateMapFragment) void {
|
|
||||||
if(@atomicRmw(u16, &mapFragment.refCount.raw, .Sub, 1, .monotonic) == 1) {
|
|
||||||
main.globalAllocator.destroy(mapFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cacheInit(pos: ClimateMapFragmentPosition) *ClimateMapFragment {
|
fn cacheInit(pos: ClimateMapFragmentPosition) *ClimateMapFragment {
|
||||||
const mapFragment = main.globalAllocator.create(ClimateMapFragment);
|
const mapFragment = main.globalAllocator.create(ClimateMapFragment);
|
||||||
mapFragment.init(pos.wx, pos.wy);
|
mapFragment.init(pos.wx, pos.wy);
|
||||||
@ -127,11 +134,9 @@ pub fn deinit() void {
|
|||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call deinit on the result.
|
fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32) *ClimateMapFragment {
|
||||||
fn getOrGenerateFragment(wx: i32, wy: i32) *ClimateMapFragment {
|
|
||||||
const compare = ClimateMapFragmentPosition{.wx = wx, .wy = wy};
|
const compare = ClimateMapFragmentPosition{.wx = wx, .wy = wy};
|
||||||
const result = cache.findOrCreate(compare, cacheInit);
|
const result = cache.findOrCreate(compare, cacheInit, ClimateMapFragment.increaseRefCount);
|
||||||
std.debug.assert(@atomicRmw(u16, &result.refCount.raw, .Add, 1, .monotonic) != 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +150,8 @@ pub fn getBiomeMap(allocator: NeverFailingAllocator, wx: i32, wy: i32, width: u3
|
|||||||
while(wxEnd -% x >= 0) : (x +%= ClimateMapFragment.mapSize) {
|
while(wxEnd -% x >= 0) : (x +%= ClimateMapFragment.mapSize) {
|
||||||
var y = wzStart;
|
var y = wzStart;
|
||||||
while(wzEnd -% y >= 0) : (y +%= ClimateMapFragment.mapSize) {
|
while(wzEnd -% y >= 0) : (y +%= ClimateMapFragment.mapSize) {
|
||||||
const mapPiece = getOrGenerateFragment(x, y);
|
const mapPiece = getOrGenerateFragmentAndIncreaseRefCount(x, y);
|
||||||
defer mapFragmentDeinit(mapPiece);
|
defer mapPiece.decreaseRefCount();
|
||||||
// Offset of the indices in the result map:
|
// Offset of the indices in the result map:
|
||||||
const xOffset = (x -% wx) >> MapFragment.biomeShift;
|
const xOffset = (x -% wx) >> MapFragment.biomeShift;
|
||||||
const yOffset = (y -% wy) >> MapFragment.biomeShift;
|
const yOffset = (y -% wy) >> MapFragment.biomeShift;
|
||||||
|
@ -29,8 +29,15 @@ pub const LightMapFragment = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increaseRefCount(self: *LightMapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decreaseRefCount(self: *LightMapFragment) void {
|
pub fn decreaseRefCount(self: *LightMapFragment) void {
|
||||||
if(@atomicRmw(u16, &self.refCount.raw, .Sub, 1, .monotonic) == 1) {
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
main.globalAllocator.destroy(self);
|
main.globalAllocator.destroy(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,8 +58,8 @@ var cache: Cache(LightMapFragment, cacheSize, associativity, LightMapFragment.de
|
|||||||
fn cacheInit(pos: MapFragmentPosition) *LightMapFragment {
|
fn cacheInit(pos: MapFragmentPosition) *LightMapFragment {
|
||||||
const mapFragment = main.globalAllocator.create(LightMapFragment);
|
const mapFragment = main.globalAllocator.create(LightMapFragment);
|
||||||
mapFragment.init(pos.wx, pos.wy, pos.voxelSize);
|
mapFragment.init(pos.wx, pos.wy, pos.voxelSize);
|
||||||
const surfaceMap = terrain.SurfaceMap.getOrGenerateFragment(pos.wx, pos.wy, pos.voxelSize);
|
const surfaceMap = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(pos.wx, pos.wy, pos.voxelSize);
|
||||||
defer surfaceMap.deinit();
|
defer surfaceMap.decreaseRefCount();
|
||||||
comptime std.debug.assert(LightMapFragment.mapSize == terrain.SurfaceMap.MapFragment.mapSize);
|
comptime std.debug.assert(LightMapFragment.mapSize == terrain.SurfaceMap.MapFragment.mapSize);
|
||||||
for(0..LightMapFragment.mapSize) |x| {
|
for(0..LightMapFragment.mapSize) |x| {
|
||||||
for(0..LightMapFragment.mapSize) |y| {
|
for(0..LightMapFragment.mapSize) |y| {
|
||||||
@ -68,14 +75,12 @@ pub fn deinit() void {
|
|||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call decreaseRefCount on the result.
|
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);
|
const result = cache.findOrCreate(compare, cacheInit, LightMapFragment.increaseRefCount);
|
||||||
std.debug.assert(@atomicRmw(u16, &result.refCount.raw, .Add, 1, .monotonic) != 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
@ -78,8 +78,17 @@ pub const MapFragment = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *MapFragment) void {
|
pub fn increaseRefCount(self: *MapFragment) void {
|
||||||
mapFragmentDeinit(self);
|
const prevVal = self.refCount.fetchAdd(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decreaseRefCount(self: *MapFragment) void {
|
||||||
|
const prevVal = self.refCount.fetchSub(1, .monotonic);
|
||||||
|
std.debug.assert(prevVal != 0);
|
||||||
|
if(prevVal == 1) {
|
||||||
|
main.globalAllocator.destroy(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBiome(self: *MapFragment, wx: i32, wy: i32) *const Biome {
|
pub fn getBiome(self: *MapFragment, wx: i32, wy: i32) *const Biome {
|
||||||
@ -124,7 +133,7 @@ pub const MapGenerator = 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; // ~400MiB MiB Cache size
|
const associativity = 8; // ~400MiB MiB Cache size
|
||||||
var cache: Cache(MapFragment, cacheSize, associativity, mapFragmentDeinit) = .{};
|
var cache: Cache(MapFragment, cacheSize, associativity, MapFragment.decreaseRefCount) = .{};
|
||||||
var profile: TerrainGenerationProfile = undefined;
|
var profile: TerrainGenerationProfile = undefined;
|
||||||
|
|
||||||
pub fn initGenerators() void {
|
pub fn initGenerators() void {
|
||||||
@ -138,12 +147,6 @@ pub fn deinitGenerators() void {
|
|||||||
MapGenerator.generatorRegistry.clearAndFree(main.globalAllocator.allocator);
|
MapGenerator.generatorRegistry.clearAndFree(main.globalAllocator.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapFragmentDeinit(mapFragment: *MapFragment) void {
|
|
||||||
if(@atomicRmw(u16, &mapFragment.refCount.raw, .Sub, 1, .monotonic) == 1) {
|
|
||||||
main.globalAllocator.destroy(mapFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cacheInit(pos: MapFragmentPosition) *MapFragment {
|
fn cacheInit(pos: MapFragmentPosition) *MapFragment {
|
||||||
const mapFragment = main.globalAllocator.create(MapFragment);
|
const mapFragment = main.globalAllocator.create(MapFragment);
|
||||||
mapFragment.init(pos.wx, pos.wy, pos.voxelSize);
|
mapFragment.init(pos.wx, pos.wy, pos.voxelSize);
|
||||||
@ -161,13 +164,12 @@ pub fn deinit() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call deinit on the result.
|
/// Call deinit on the result.
|
||||||
pub fn getOrGenerateFragment(wx: i32, wy: i32, voxelSize: u31) *MapFragment {
|
pub fn getOrGenerateFragmentAndIncreaseRefCount(wx: i32, wy: i32, voxelSize: u31) *MapFragment {
|
||||||
const compare = MapFragmentPosition.init(
|
const compare = MapFragmentPosition.init(
|
||||||
wx & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize-1),
|
wx & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize-1),
|
||||||
wy & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize-1),
|
wy & ~@as(i32, MapFragment.mapMask*voxelSize | voxelSize-1),
|
||||||
voxelSize
|
voxelSize
|
||||||
);
|
);
|
||||||
const result = cache.findOrCreate(compare, cacheInit);
|
const result = cache.findOrCreate(compare, cacheInit, MapFragment.increaseRefCount);
|
||||||
std.debug.assert(@atomicRmw(u16, &result.refCount.raw, .Add, 1, .monotonic) != 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
@ -127,7 +127,7 @@ const ChunkManager = struct {
|
|||||||
|
|
||||||
pub fn run(self: *LightMapLoadTask) void {
|
pub fn run(self: *LightMapLoadTask) void {
|
||||||
defer self.clean();
|
defer self.clean();
|
||||||
const map = terrain.LightMap.getOrGenerateFragment(self.pos.wx, self.pos.wy, self.pos.voxelSize);
|
const map = terrain.LightMap.getOrGenerateFragmentAndIncreaseRefCount(self.pos.wx, self.pos.wy, self.pos.voxelSize);
|
||||||
defer map.decreaseRefCount();
|
defer map.decreaseRefCount();
|
||||||
if(self.source) |source| {
|
if(self.source) |source| {
|
||||||
main.network.Protocols.lightMapTransmission.sendLightMap(source.conn, map);
|
main.network.Protocols.lightMapTransmission.sendLightMap(source.conn, map);
|
||||||
@ -204,8 +204,8 @@ const ChunkManager = struct {
|
|||||||
// 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.
|
||||||
pub fn getOrGenerateChunk(pos: ChunkPosition) *Chunk {
|
pub fn getOrGenerateChunk(pos: ChunkPosition) *Chunk { // TODO: This is not thread safe! The chunk could get removed from the cache while in use. Reference counting should probably be used here.
|
||||||
return chunkCache.findOrCreate(pos, chunkInitFunctionForCache);
|
return chunkCache.findOrCreate(pos, chunkInitFunctionForCache, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getChunkFromCache(pos: ChunkPosition) ?*Chunk {
|
pub fn getChunkFromCache(pos: ChunkPosition) ?*Chunk {
|
||||||
@ -368,8 +368,8 @@ pub const ServerWorld = struct {
|
|||||||
std.log.info("Trying ({}, {})", .{self.spawn[0], self.spawn[1]});
|
std.log.info("Trying ({}, {})", .{self.spawn[0], self.spawn[1]});
|
||||||
if(self.isValidSpawnLocation(self.spawn[0], self.spawn[1])) break;
|
if(self.isValidSpawnLocation(self.spawn[0], self.spawn[1])) break;
|
||||||
}
|
}
|
||||||
const map = terrain.SurfaceMap.getOrGenerateFragment(self.spawn[0], self.spawn[1], 1);
|
const map = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(self.spawn[0], self.spawn[1], 1);
|
||||||
defer map.deinit();
|
defer map.decreaseRefCount();
|
||||||
self.spawn[2] = @intFromFloat(map.getHeight(self.spawn[0], self.spawn[1]) + 1);
|
self.spawn[2] = @intFromFloat(map.getHeight(self.spawn[0], self.spawn[1]) + 1);
|
||||||
}
|
}
|
||||||
self.generated = true;
|
self.generated = true;
|
||||||
@ -401,8 +401,8 @@ pub const ServerWorld = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn isValidSpawnLocation(_: *ServerWorld, wx: i32, wy: i32) bool {
|
fn isValidSpawnLocation(_: *ServerWorld, wx: i32, wy: i32) bool {
|
||||||
const map = terrain.SurfaceMap.getOrGenerateFragment(wx, wy, 1);
|
const map = terrain.SurfaceMap.getOrGenerateFragmentAndIncreaseRefCount(wx, wy, 1);
|
||||||
defer map.deinit();
|
defer map.decreaseRefCount();
|
||||||
return map.getBiome(wx, wy).isValidPlayerSpawn;
|
return map.getBiome(wx, wy).isValidPlayerSpawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1387,12 +1387,13 @@ pub fn Cache(comptime T: type, comptime numberOfBuckets: u32, comptime bucketSiz
|
|||||||
cacheMisses: Atomic(usize) = Atomic(usize).init(0),
|
cacheMisses: Atomic(usize) = Atomic(usize).init(0),
|
||||||
|
|
||||||
/// Tries to find the entry that fits to the supplied hashable.
|
/// Tries to find the entry that fits to the supplied hashable.
|
||||||
pub fn find(self: *@This(), compareAndHash: anytype) ?*T {
|
pub fn find(self: *@This(), compareAndHash: anytype, comptime postGetFunction: ?fn(*T) void) ?*T {
|
||||||
const index: u32 = compareAndHash.hashCode() & hashMask;
|
const index: u32 = compareAndHash.hashCode() & hashMask;
|
||||||
_ = @atomicRmw(usize, &self.cacheRequests.raw, .Add, 1, .monotonic);
|
_ = @atomicRmw(usize, &self.cacheRequests.raw, .Add, 1, .monotonic);
|
||||||
self.buckets[index].mutex.lock();
|
self.buckets[index].mutex.lock();
|
||||||
defer self.buckets[index].mutex.unlock();
|
defer self.buckets[index].mutex.unlock();
|
||||||
if(self.buckets[index].find(compareAndHash)) |item| {
|
if(self.buckets[index].find(compareAndHash)) |item| {
|
||||||
|
if(postGetFunction) |fun| fun(item);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
_ = @atomicRmw(usize, &self.cacheMisses.raw, .Add, 1, .monotonic);
|
_ = @atomicRmw(usize, &self.cacheMisses.raw, .Add, 1, .monotonic);
|
||||||
@ -1420,11 +1421,13 @@ pub fn Cache(comptime T: type, comptime numberOfBuckets: u32, comptime bucketSiz
|
|||||||
return self.buckets[index].add(item);
|
return self.buckets[index].add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn findOrCreate(self: *@This(), compareAndHash: anytype, comptime initFunction: fn(@TypeOf(compareAndHash)) *T) *T {
|
pub fn findOrCreate(self: *@This(), compareAndHash: anytype, comptime initFunction: fn(@TypeOf(compareAndHash)) *T, comptime postGetFunction: ?fn(*T) void) *T {
|
||||||
const index: u32 = compareAndHash.hashCode() & hashMask;
|
const index: u32 = compareAndHash.hashCode() & hashMask;
|
||||||
self.buckets[index].mutex.lock();
|
self.buckets[index].mutex.lock();
|
||||||
defer self.buckets[index].mutex.unlock();
|
defer self.buckets[index].mutex.unlock();
|
||||||
return self.buckets[index].findOrCreate(compareAndHash, initFunction);
|
const result = self.buckets[index].findOrCreate(compareAndHash, initFunction);
|
||||||
|
if(postGetFunction) |fun| fun(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user