diff --git a/src/assets.zig b/src/assets.zig index b13ceee9..3c0b1901 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -25,7 +25,7 @@ pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons }; defer dir.close(); - var walker = dir.walk(main.globalAllocator.allocator) catch unreachable; + var walker = dir.walk(main.stackAllocator.allocator) catch unreachable; defer walker.deinit(); while(walker.next() catch |err| blk: { @@ -69,7 +69,7 @@ pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: ma }; defer dir.close(); - var walker = dir.walk(main.globalAllocator.allocator) catch unreachable; + var walker = dir.walk(main.stackAllocator.allocator) catch unreachable; defer walker.deinit(); while(walker.next() catch |err| blk: { @@ -90,9 +90,9 @@ pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: ma } pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(JsonElement), items: *std.StringHashMap(JsonElement), biomes: *std.StringHashMap(JsonElement), recipes: *main.List([]const u8)) void { - var addons = main.List(std.fs.Dir).init(main.globalAllocator); + var addons = main.List(std.fs.Dir).init(main.stackAllocator); defer addons.deinit(); - var addonNames = main.List([]const u8).init(main.globalAllocator); + var addonNames = main.List([]const u8).init(main.stackAllocator); defer addonNames.deinit(); { // Find all the sub-directories to the assets folder. @@ -111,13 +111,13 @@ pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u std.log.err("Got error while reading addon {s} from {s}: {s}", .{addon.name, assetPath, @errorName(err)}); continue; }); - addonNames.append(main.globalAllocator.dupe(u8, addon.name)); + addonNames.append(main.stackAllocator.dupe(u8, addon.name)); } } } defer for(addons.items, addonNames.items) |*dir, addonName| { dir.close(); - main.globalAllocator.free(addonName); + main.stackAllocator.free(addonName); }; readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "blocks", blocks); @@ -224,13 +224,13 @@ var loadedAssets: bool = false; pub fn loadWorldAssets(assetFolder: []const u8, palette: *BlockPalette) !void { if(loadedAssets) return; // The assets already got loaded by the server. loadedAssets = true; - var blocks = commonBlocks.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable; + var blocks = commonBlocks.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer blocks.clearAndFree(); - var items = commonItems.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable; + var items = commonItems.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer items.clearAndFree(); - var biomes = commonBiomes.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable; + var biomes = commonBiomes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer biomes.clearAndFree(); - var recipes = main.List([]const u8).init(main.globalAllocator); + var recipes = main.List([]const u8).init(main.stackAllocator); recipes.appendSlice(commonRecipes.items); defer recipes.clearAndFree(); diff --git a/src/graphics.zig b/src/graphics.zig index eefc2e58..581fba6c 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -391,10 +391,8 @@ pub const draw = struct { } pub inline fn print(comptime format: []const u8, args: anytype, x: f32, y: f32, fontSize: f32, alignment: TextBuffer.Alignment) void { - var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator); - const allocator = stackFallback.get(); - const string = std.fmt.allocPrint(allocator, format, args) catch unreachable; - defer allocator.free(string); + const string = std.fmt.allocPrint(main.stackAllocator.allocator, format, args) catch unreachable; + defer main.stackAllocator.free(string); text(string, x, y ,fontSize, alignment); } }; @@ -560,13 +558,11 @@ pub const TextBuffer = struct { pub fn init(allocator: NeverFailingAllocator, text: []const u8, initialFontEffect: FontEffect, showControlCharacters: bool, alignment: Alignment) TextBuffer { var self: TextBuffer = undefined; self.alignment = alignment; - var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator); - const stackFallbackAllocator = stackFallback.get(); // Parse the input text: var parser = Parser { .unicodeIterator = std.unicode.Utf8Iterator{.bytes = text, .i = 0}, .currentFontEffect = initialFontEffect, - .parsedText = main.List(u32).init(.{.allocator = stackFallbackAllocator, .IAssertThatTheProvidedAllocatorCantFail = {}}), + .parsedText = main.List(u32).init(main.stackAllocator), .fontEffects = main.List(FontEffect).init(allocator), .characterIndex = main.List(u32).init(allocator), .showControlCharacters = showControlCharacters @@ -1040,9 +1036,7 @@ const TextRendering = struct { } fn renderText(text: []const u8, x: f32, y: f32, fontSize: f32, initialFontEffect: TextBuffer.FontEffect, alignment: TextBuffer.Alignment) void { - var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator); - const allocator = stackFallback.get(); - const buf = TextBuffer.init(.{.allocator = allocator, .IAssertThatTheProvidedAllocatorCantFail = {}}, text, initialFontEffect, false, alignment); + const buf = TextBuffer.init(main.stackAllocator, text, initialFontEffect, false, alignment); defer buf.deinit(); buf.render(x, y, fontSize); @@ -1530,7 +1524,7 @@ pub const TextureArray = struct { const maxLOD = if(mipmapping) 1 + std.math.log2_int(u31, @min(maxWidth, maxHeight)) else 1; c.glTexStorage3D(c.GL_TEXTURE_2D_ARRAY, maxLOD, c.GL_RGBA8, maxWidth, maxHeight, @intCast(images.len)); - var arena = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator); + var arena = main.utils.NeverFailingArenaAllocator.init(main.stackAllocator); defer arena.deinit(); const lodBuffer: [][]Color = arena.allocator().alloc([]Color, maxLOD); for(lodBuffer, 0..) |*buffer, i| { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index efc43cb1..642f32a4 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -182,12 +182,12 @@ pub fn deinit() void { } fn save() void { - const guiJson = JsonElement.initObject(main.globalAllocator); - defer guiJson.free(main.globalAllocator); + const guiJson = JsonElement.initObject(main.stackAllocator); + defer guiJson.free(main.stackAllocator); for(windowList.items) |window| { - const windowJson = JsonElement.initObject(main.globalAllocator); + const windowJson = JsonElement.initObject(main.stackAllocator); for(window.relativePosition, 0..) |relPos, i| { - const relPosJson = JsonElement.initObject(main.globalAllocator); + const relPosJson = JsonElement.initObject(main.stackAllocator); switch(relPos) { .ratio => |ratio| { relPosJson.put("type", "ratio"); @@ -222,13 +222,13 @@ fn save() void { } fn load() void { - const json: JsonElement = main.files.readToJson(main.globalAllocator, "gui_layout.json") catch |err| blk: { + const json: JsonElement = main.files.readToJson(main.stackAllocator, "gui_layout.json") catch |err| blk: { if(err != error.FileNotFound) { std.log.err("Could not read gui_layout.json: {s}", .{@errorName(err)}); } break :blk JsonElement{.JsonNull={}}; }; - defer json.free(main.globalAllocator); + defer json.free(main.stackAllocator); for(windowList.items) |window| { const windowJson = json.getChild(window.id); @@ -649,7 +649,7 @@ pub const inventory = struct { if(carriedItemStack.amount == 0) if(hoveredItemSlot) |hovered| { if(hovered.itemStack.item) |item| { const tooltip = item.getTooltip(); - var textBuffer: graphics.TextBuffer = graphics.TextBuffer.init(main.globalAllocator, tooltip, .{}, false, .left); + var textBuffer: graphics.TextBuffer = graphics.TextBuffer.init(main.stackAllocator, tooltip, .{}, false, .left); defer textBuffer.deinit(); var size = textBuffer.calculateLineBreaks(16, 256); size[0] = 0; diff --git a/src/itemdrop.zig b/src/itemdrop.zig index a9b3dda3..fd041de4 100644 --- a/src/itemdrop.zig +++ b/src/itemdrop.zig @@ -275,10 +275,10 @@ pub const ItemDropManager = struct { self.mutex.lock(); defer self.mutex.unlock(); if(self.size == maxCapacity) { - const json = itemStack.store(main.globalAllocator); - defer json.free(main.globalAllocator); + const json = itemStack.store(main.stackAllocator); + defer json.free(main.stackAllocator); const string = json.toString(main.stackAllocator); - defer main.globalAllocator.free(string); + defer main.stackAllocator.free(string); std.log.err("Item drop capacitiy limit reached. Failed to add itemStack: {s}", .{string}); if(itemStack.item) |item| { item.deinit(); diff --git a/src/items.zig b/src/items.zig index fbc110d8..773b9ce3 100644 --- a/src/items.zig +++ b/src/items.zig @@ -441,7 +441,7 @@ const TextureGenerator = struct { var pixelMaterials: [16][16]PixelData = undefined; for(0..16) |x| { for(0..16) |y| { - pixelMaterials[x][y] = PixelData.init(main.globalAllocator); + pixelMaterials[x][y] = PixelData.init(main.stackAllocator); } } @@ -1331,19 +1331,19 @@ pub fn register(_: []const u8, texturePath: []const u8, replacementTexturePath: } pub fn registerRecipes(file: []const u8) void { - var shortcuts = std.StringHashMap(*BaseItem).init(main.globalAllocator.allocator); + var shortcuts = std.StringHashMap(*BaseItem).init(main.stackAllocator.allocator); defer shortcuts.deinit(); defer { var keyIterator = shortcuts.keyIterator(); while(keyIterator.next()) |key| { - main.globalAllocator.free(key.*); + main.stackAllocator.free(key.*); } } - var items = main.List(*BaseItem).init(main.globalAllocator); + var items = main.List(*BaseItem).init(main.stackAllocator); defer items.deinit(); - var itemAmounts = main.List(u16).init(main.globalAllocator); + var itemAmounts = main.List(u16).init(main.stackAllocator); defer itemAmounts.deinit(); - var string = main.List(u8).init(main.globalAllocator); + var string = main.List(u8).init(main.stackAllocator); defer string.deinit(); var lines = std.mem.split(u8, file, "\n"); while(lines.next()) |line| { diff --git a/src/network.zig b/src/network.zig index 6e08eebb..da41cfb6 100644 --- a/src/network.zig +++ b/src/network.zig @@ -97,7 +97,7 @@ const Socket = struct { } fn resolveIP(addr: []const u8) !u32 { - const list = try std.net.getAddressList(main.globalAllocator.allocator, addr, settings.defaultPort); + const list = try std.net.getAddressList(main.stackAllocator.allocator, addr, settings.defaultPort); defer list.deinit(); return list.addrs[0].in.sa.addr; } @@ -605,8 +605,8 @@ pub const Protocols = struct { conn.handShakeState.store(data[0], .Monotonic); switch(data[0]) { stepUserData => { - const json = JsonElement.parseFromString(main.globalAllocator, data[1..]); - defer json.free(main.globalAllocator); + const json = JsonElement.parseFromString(main.stackAllocator, data[1..]); + defer json.free(main.stackAllocator); const name = json.get([]const u8, "name", "unnamed"); const version = json.get([]const u8, "version", "unknown"); std.log.info("User {s} joined using version {s}.", .{name, version}); @@ -617,7 +617,7 @@ pub const Protocols = struct { defer main.stackAllocator.free(path); var dir = try std.fs.cwd().openDir(path, .{.iterate = true}); defer dir.close(); - var arrayList = main.List(u8).init(main.globalAllocator); + var arrayList = main.List(u8).init(main.stackAllocator); defer arrayList.deinit(); arrayList.append(stepAssets); try utils.Compression.pack(dir, arrayList.writer()); @@ -627,13 +627,13 @@ pub const Protocols = struct { // TODO: conn.user.?.initPlayer(name); - const jsonObject = JsonElement.initObject(main.globalAllocator); - defer jsonObject.free(main.globalAllocator); - jsonObject.put("player", conn.user.?.player.save(main.globalAllocator)); + const jsonObject = JsonElement.initObject(main.stackAllocator); + defer jsonObject.free(main.stackAllocator); + jsonObject.put("player", conn.user.?.player.save(main.stackAllocator)); // TODO: // jsonObject.put("player_id", ((User)conn).player.id); // jsonObject.put("blockPalette", Server.world.blockPalette.save()); - const spawn = JsonElement.initObject(main.globalAllocator); + const spawn = JsonElement.initObject(main.stackAllocator); spawn.put("x", main.server.world.?.spawn[0]); spawn.put("y", main.server.world.?.spawn[1]); spawn.put("z", main.server.world.?.spawn[2]); @@ -657,8 +657,8 @@ pub const Protocols = struct { try utils.Compression.unpack(dir, data[1..]); }, stepServerData => { - const json = JsonElement.parseFromString(main.globalAllocator, data[1..]); - defer json.free(main.globalAllocator); + const json = JsonElement.parseFromString(main.stackAllocator, data[1..]); + defer json.free(main.stackAllocator); try conn.manager.world.?.finishHandshake(json); conn.handShakeState.store(stepComplete, .Monotonic); conn.handShakeWaiting.broadcast(); // Notify the waiting client thread. @@ -680,8 +680,8 @@ pub const Protocols = struct { } pub fn clientSide(conn: *Connection, name: []const u8) void { - const jsonObject = JsonElement.initObject(main.globalAllocator); - defer jsonObject.free(main.globalAllocator); + const jsonObject = JsonElement.initObject(main.stackAllocator); + defer jsonObject.free(main.stackAllocator); jsonObject.putOwnedString("version", settings.version); jsonObject.putOwnedString("name", name); const prefix = [1]u8 {stepUserData}; @@ -869,8 +869,8 @@ pub const Protocols = struct { pub const entity = struct { pub const id: u8 = 8; fn receive(conn: *Connection, data: []const u8) !void { - const jsonArray = JsonElement.parseFromString(main.globalAllocator, data); - defer jsonArray.free(main.globalAllocator); + const jsonArray = JsonElement.parseFromString(main.stackAllocator, data); + defer jsonArray.free(main.stackAllocator); var i: u32 = 0; while(i < jsonArray.JsonArray.items.len) : (i += 1) { const elem = jsonArray.JsonArray.items[i]; @@ -1065,8 +1065,8 @@ pub const Protocols = struct { // ); }, type_itemStackCollect => { - const json = JsonElement.parseFromString(main.globalAllocator, data[1..]); - defer json.free(main.globalAllocator); + const json = JsonElement.parseFromString(main.stackAllocator, data[1..]); + defer json.free(main.stackAllocator); const item = items.Item.init(json) catch |err| { std.log.err("Error {s} while collecting item {s}. Ignoring it.", .{@errorName(err), data[1..]}); return; @@ -1083,8 +1083,8 @@ pub const Protocols = struct { }, type_timeAndBiome => { if(conn.manager.world) |world| { - const json = JsonElement.parseFromString(main.globalAllocator, data[1..]); - defer json.free(main.globalAllocator); + const json = JsonElement.parseFromString(main.stackAllocator, data[1..]); + defer json.free(main.stackAllocator); const expectedTime = json.get(i64, "time", 0); var curTime = world.gameTime.load(.Monotonic); if(@abs(curTime -% expectedTime) >= 1000) { @@ -1155,8 +1155,8 @@ pub const Protocols = struct { pub fn sendInventory_full(conn: *Connection, inv: Inventory) void { - const json = inv.save(main.globalAllocator); - defer json.free(main.globalAllocator); + const json = inv.save(main.stackAllocator); + defer json.free(main.stackAllocator); const string = json.toString(main.stackAllocator); defer main.stackAllocator.free(string); addHeaderAndSendImportant(conn, type_inventoryFull, string); @@ -1169,8 +1169,8 @@ pub const Protocols = struct { } pub fn itemStackDrop(conn: *Connection, stack: ItemStack, pos: Vec3d, dir: Vec3f, vel: f32) void { - const jsonObject = stack.store(main.globalAllocator); - defer jsonObject.free(main.globalAllocator); + const jsonObject = stack.store(main.stackAllocator); + defer jsonObject.free(main.stackAllocator); jsonObject.put("x", pos[0]); jsonObject.put("y", pos[1]); jsonObject.put("z", pos[2]); @@ -1184,16 +1184,16 @@ pub const Protocols = struct { } pub fn itemStackCollect(conn: *Connection, stack: ItemStack) void { - const json = stack.store(main.globalAllocator); - defer json.free(main.globalAllocator); + const json = stack.store(main.stackAllocator); + defer json.free(main.stackAllocator); const string = json.toString(main.stackAllocator); defer main.stackAllocator.free(string); addHeaderAndSendImportant(conn, type_itemStackCollect, string); } pub fn sendTimeAndBiome(conn: *Connection, world: *const main.server.ServerWorld) void { - const json = JsonElement.initObject(main.globalAllocator); - defer json.free(main.globalAllocator); + const json = JsonElement.initObject(main.stackAllocator); + defer json.free(main.stackAllocator); json.put("time", world.gameTime); const pos = conn.user.?.player.pos; json.put("biome", (world.getBiome(@intFromFloat(pos[0]), @intFromFloat(pos[1]), @intFromFloat(pos[2]))).id); @@ -1483,9 +1483,9 @@ pub const Connection = struct { self.mutex.lock(); defer self.mutex.unlock(); - var runLengthEncodingStarts: main.List(u32) = main.List(u32).init(main.globalAllocator); + var runLengthEncodingStarts: main.List(u32) = main.List(u32).init(main.stackAllocator); defer runLengthEncodingStarts.deinit(); - var runLengthEncodingLengths: main.List(u32) = main.List(u32).init(main.globalAllocator); + var runLengthEncodingLengths: main.List(u32) = main.List(u32).init(main.stackAllocator); defer runLengthEncodingLengths.deinit(); for(self.receivedPackets) |list| { diff --git a/src/renderer.zig b/src/renderer.zig index 33329f44..29ae2068 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -486,19 +486,19 @@ pub const MenuBackGround = struct { var dir = try std.fs.cwd().makeOpenPath("assets/backgrounds", .{.iterate = true}); defer dir.close(); - var walker = try dir.walk(main.globalAllocator.allocator); + var walker = try dir.walk(main.stackAllocator.allocator); defer walker.deinit(); - var fileList = main.List([]const u8).init(main.globalAllocator); + var fileList = main.List([]const u8).init(main.stackAllocator); defer { for(fileList.items) |fileName| { - main.globalAllocator.free(fileName); + main.stackAllocator.free(fileName); } fileList.deinit(); } while(try walker.next()) |entry| { if(entry.kind == .file and std.ascii.endsWithIgnoreCase(entry.basename, ".png")) { - fileList.append(main.globalAllocator.dupe(u8, entry.path)); + fileList.append(main.stackAllocator.dupe(u8, entry.path)); } } if(fileList.items.len == 0) { diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index c563e111..37d0efd8 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -574,7 +574,7 @@ pub const ChunkMesh = struct { fn initLight(self: *ChunkMesh) void { self.mutex.lock(); - var lightEmittingBlocks = main.List([3]u8).init(main.globalAllocator); + var lightEmittingBlocks = main.List([3]u8).init(main.stackAllocator); defer lightEmittingBlocks.deinit(); var x: u8 = 0; while(x < chunk.chunkSize): (x += 1) { diff --git a/src/renderer/lighting.zig b/src/renderer/lighting.zig index 4e1c850f..e137e0ab 100644 --- a/src/renderer/lighting.zig +++ b/src/renderer/lighting.zig @@ -88,7 +88,7 @@ pub const ChannelChunk = struct { var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6; defer { for(&neighborLists) |*list| { - list.deinit(lightQueue.allocator); + list.deinit(main.stackAllocator); } } @@ -108,7 +108,7 @@ pub const ChannelChunk = struct { } if(result.value == 0) continue; if(nx < 0 or nx >= chunk.chunkSize or ny < 0 or ny >= chunk.chunkSize or nz < 0 or nz >= chunk.chunkSize) { - neighborLists[neighbor].append(lightQueue.allocator, result); + neighborLists[neighbor].append(main.stackAllocator, result); continue; } const neighborIndex = chunk.getIndex(nx, ny, nz); @@ -136,7 +136,7 @@ pub const ChannelChunk = struct { var constructiveList: main.ListUnmanaged(PositionEntry) = .{}; defer { for(&neighborLists) |*list| { - list.deinit(lightQueue.allocator); + list.deinit(main.stackAllocator); } } var isFirstIteration: bool = isFirstBlock; @@ -146,7 +146,7 @@ pub const ChannelChunk = struct { const index = chunk.getIndex(entry.x, entry.y, entry.z); if(entry.value != self.data[index].load(.Unordered)) { if(self.data[index].load(.Unordered) != 0) { - constructiveList.append(lightQueue.allocator, .{.x = entry.x, .y = entry.y, .z = entry.z}); + constructiveList.append(main.stackAllocator, .{.x = entry.x, .y = entry.y, .z = entry.z}); } continue; } @@ -163,7 +163,7 @@ pub const ChannelChunk = struct { result.value -|= 8*|@as(u8, @intCast(self.ch.pos.voxelSize)); } if(nx < 0 or nx >= chunk.chunkSize or ny < 0 or ny >= chunk.chunkSize or nz < 0 or nz >= chunk.chunkSize) { - neighborLists[neighbor].append(lightQueue.allocator, result); + neighborLists[neighbor].append(main.stackAllocator, result); continue; } const neighborIndex = chunk.getIndex(nx, ny, nz); @@ -181,7 +181,7 @@ pub const ChannelChunk = struct { for(0..6) |neighbor| { if(neighborLists[neighbor].items.len == 0) continue; const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue; - constructiveEntries.append(lightQueue.allocator, .{ + constructiveEntries.append(main.stackAllocator, .{ .mesh = neighborMesh, .entries = neighborMesh.lightingData[@intFromEnum(self.channel)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries), }); @@ -217,12 +217,7 @@ pub const ChannelChunk = struct { } pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) void { - const buf = main.stackAllocator.alloc(u8, 1 << 16); - defer main.stackAllocator.free(buf); - var bufferFallback = main.utils.BufferFallbackAllocator.init(buf, main.globalAllocator); - var arena = main.utils.NeverFailingArenaAllocator.init(bufferFallback.allocator()); - defer arena.deinit(); - var lightQueue = main.utils.CircularBufferQueue(Entry).init(arena.allocator(), 1 << 10); + var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12); defer lightQueue.deinit(); for(lights) |pos| { const index = chunk.getIndex(pos[0], pos[1], pos[2]); @@ -280,20 +275,15 @@ pub const ChannelChunk = struct { } pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8) void { - const buf = main.stackAllocator.alloc(u8, 1 << 16); - defer main.stackAllocator.free(buf); - var bufferFallback = main.utils.BufferFallbackAllocator.init(buf, main.globalAllocator); - var arena = main.utils.NeverFailingArenaAllocator.init(bufferFallback.allocator()); - defer arena.deinit(); - var lightQueue = main.utils.CircularBufferQueue(Entry).init(arena.allocator(), 1 << 10); + var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12); defer lightQueue.deinit(); for(lights) |pos| { const index = chunk.getIndex(pos[0], pos[1], pos[2]); lightQueue.enqueue(.{.x = @intCast(pos[0]), .y = @intCast(pos[1]), .z = @intCast(pos[2]), .value = self.data[index].load(.Unordered), .sourceDir = 6}); } var constructiveEntries: main.ListUnmanaged(ChunkEntries) = .{}; - defer constructiveEntries.deinit(arena.allocator()); - constructiveEntries.append(arena.allocator(), .{ + defer constructiveEntries.deinit(main.stackAllocator); + constructiveEntries.append(main.stackAllocator, .{ .mesh = null, .entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true), }); @@ -301,7 +291,7 @@ pub const ChannelChunk = struct { const mesh = entries.mesh; defer if(mesh) |_mesh| _mesh.decreaseRefCount(); var entryList = entries.entries; - defer entryList.deinit(arena.allocator()); + defer entryList.deinit(main.stackAllocator); 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); diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index 50b41540..ff1a471d 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -531,9 +531,9 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V network.Protocols.genericUpdate.sendRenderDistance(conn, renderDistance); } - var meshRequests = main.List(chunk.ChunkPosition).init(main.globalAllocator); + var meshRequests = main.List(chunk.ChunkPosition).init(main.stackAllocator); defer meshRequests.deinit(); - var mapRequests = main.List(LightMap.MapFragmentPosition).init(main.globalAllocator); + var mapRequests = main.List(LightMap.MapFragmentPosition).init(main.stackAllocator); defer mapRequests.deinit(); const olderPx = lastPx; @@ -568,7 +568,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V }; // TODO: Is there a way to combine this with minecraft's approach? - var searchList = std.PriorityQueue(OcclusionData, void, OcclusionData.compare).init(main.globalAllocator.allocator, {}); + var searchList = std.PriorityQueue(OcclusionData, void, OcclusionData.compare).init(main.stackAllocator.allocator, {}); defer searchList.deinit(); { var firstPos = chunk.ChunkPosition{ @@ -601,7 +601,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V firstPos.voxelSize *= 2; } } - var nodeList = main.List(*ChunkMeshNode).init(main.globalAllocator); + var nodeList = main.List(*ChunkMeshNode).init(main.stackAllocator); defer nodeList.deinit(); const projRotMat = game.projectionMatrix.mul(game.camera.viewMatrix); while(searchList.removeOrNull()) |data| { diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index 46ca889e..410cefd3 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -146,10 +146,10 @@ pub const Biome = struct { const structures = json.getChild("structures"); var vegetation = main.ListUnmanaged(StructureModel){}; - defer vegetation.deinit(main.globalAllocator); + defer vegetation.deinit(main.stackAllocator); for(structures.toSlice()) |elem| { if(StructureModel.initModel(elem)) |model| { - vegetation.append(main.globalAllocator, model); + vegetation.append(main.stackAllocator, model); } } self.vegetationModels = main.globalAllocator.dupe(StructureModel, vegetation.items); diff --git a/src/server/terrain/climategen/NoiseBasedVoronoi.zig b/src/server/terrain/climategen/NoiseBasedVoronoi.zig index aaaf6d42..212efd72 100644 --- a/src/server/terrain/climategen/NoiseBasedVoronoi.zig +++ b/src/server/terrain/climategen/NoiseBasedVoronoi.zig @@ -30,7 +30,7 @@ pub fn deinit() void { pub fn generateMapFragment(map: *ClimateMapFragment, worldSeed: u64) void { var seed: u64 = worldSeed; - const generator = GenerationStructure.init(main.globalAllocator, map.pos.wx, map.pos.wz, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, terrain.biomes.byTypeBiomes, seed); + const generator = GenerationStructure.init(main.stackAllocator, map.pos.wx, map.pos.wz, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, terrain.biomes.byTypeBiomes, seed); defer generator.deinit(main.stackAllocator); generator.toMap(map, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, worldSeed); @@ -327,7 +327,7 @@ const GenerationStructure = struct { } // Add some sub-biomes: - var extraBiomes = main.List(BiomePoint).init(main.globalAllocator); + var extraBiomes = main.List(BiomePoint).init(main.stackAllocator); defer extraBiomes.deinit(); for(self.chunks.mem) |chunk| { for(chunk.biomesSortedByX) |biome| { diff --git a/src/server/world.zig b/src/server/world.zig index b4795305..ffe73ce4 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -269,8 +269,8 @@ const WorldIO = struct { /// Load the seed, which is needed before custom item and ore generation. pub fn loadWorldSeed(self: WorldIO) !u64 { - const worldData: JsonElement = try self.dir.readToJson(main.globalAllocator, "world.dat"); - defer worldData.free(main.globalAllocator); + const worldData: JsonElement = try self.dir.readToJson(main.stackAllocator, "world.dat"); + defer worldData.free(main.stackAllocator); if(worldData.get(u32, "version", 0) != worldDataVersion) { std.log.err("Cannot read world file version {}. Expected version {}.", .{worldData.get(u32, "version", 0), worldDataVersion}); return error.OldWorld; @@ -279,8 +279,8 @@ const WorldIO = struct { } pub fn loadWorldData(self: WorldIO) !void { - const worldData: JsonElement = try self.dir.readToJson(main.globalAllocator, "world.dat"); - defer worldData.free(main.globalAllocator); + const worldData: JsonElement = try self.dir.readToJson(main.stackAllocator, "world.dat"); + defer worldData.free(main.stackAllocator); const entityJson = worldData.getChild("entities"); _ = entityJson; @@ -300,15 +300,15 @@ const WorldIO = struct { } pub fn saveWorldData(self: WorldIO) !void { - const worldData: JsonElement = JsonElement.initObject(main.globalAllocator); - defer worldData.free(main.globalAllocator); + const worldData: JsonElement = JsonElement.initObject(main.stackAllocator); + defer worldData.free(main.stackAllocator); worldData.put("version", worldDataVersion); worldData.put("seed", self.world.seed); worldData.put("doGameTimeCycle", self.world.doGameTimeCycle); worldData.put("gameTime", self.world.gameTime); // TODO: // worldData.put("entityCount", world.getEntities().length); - const spawnData = JsonElement.initObject(main.globalAllocator); + const spawnData = JsonElement.initObject(main.stackAllocator); spawnData.put("x", self.world.spawn[0]); spawnData.put("y", self.world.spawn[1]); spawnData.put("z", self.world.spawn[2]); @@ -366,7 +366,7 @@ pub const ServerWorld = struct { self.itemDropManager.init(main.globalAllocator, self, self.gravity); errdefer self.itemDropManager.deinit(); - var loadArena = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator); + var loadArena = main.utils.NeverFailingArenaAllocator.init(main.stackAllocator); defer loadArena.deinit(); const arenaAllocator = loadArena.allocator(); var buf: [32768]u8 = undefined; @@ -438,8 +438,8 @@ pub const ServerWorld = struct { pub fn findPlayer(self: *ServerWorld, user: *User) void { var buf: [1024]u8 = undefined; - const playerData = files.readToJson(main.globalAllocator, std.fmt.bufPrint(&buf, "saves/{s}/player/{s}.json", .{self.name, user.name}) catch "") catch .JsonNull; // TODO: Utils.escapeFolderName(user.name) - defer playerData.free(main.globalAllocator); + const playerData = files.readToJson(main.stackAllocator, std.fmt.bufPrint(&buf, "saves/{s}/player/{s}.json", .{self.name, user.name}) catch "") catch .JsonNull; // TODO: Utils.escapeFolderName(user.name) + defer playerData.free(main.stackAllocator); const player = &user.player; if(playerData == .JsonNull) { // Generate a new player: @@ -473,8 +473,8 @@ pub const ServerWorld = struct { // savePlayers(); // chunkManager.forceSave(); // ChunkIO.save(); - const itemDropJson = self.itemDropManager.store(main.globalAllocator); - defer itemDropJson.free(main.globalAllocator); + const itemDropJson = self.itemDropManager.store(main.stackAllocator); + defer itemDropJson.free(main.stackAllocator); var buf: [32768]u8 = undefined; try files.writeJson(try std.fmt.bufPrint(&buf, "saves/{s}/items.json", .{self.name}), itemDropJson); } diff --git a/src/settings.zig b/src/settings.zig index dfa41122..d0a81d68 100644 --- a/src/settings.zig +++ b/src/settings.zig @@ -41,13 +41,13 @@ pub var developerAutoEnterWorld: []const u8 = ""; pub fn init() void { - const json: JsonElement = main.files.readToJson(main.globalAllocator, "settings.json") catch |err| { + const json: JsonElement = main.files.readToJson(main.stackAllocator, "settings.json") catch |err| { if(err != error.FileNotFound) { std.log.err("Could not read settings file: {s}", .{@errorName(err)}); } return; }; - defer json.free(main.globalAllocator); + defer json.free(main.stackAllocator); inline for(@typeInfo(@This()).Struct.decls) |decl| { const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const. @@ -78,8 +78,8 @@ pub fn init() void { } pub fn deinit() void { - const jsonObject = JsonElement.initObject(main.globalAllocator); - defer jsonObject.free(main.globalAllocator); + const jsonObject = JsonElement.initObject(main.stackAllocator); + defer jsonObject.free(main.stackAllocator); inline for(@typeInfo(@This()).Struct.decls) |decl| { const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const. @@ -104,9 +104,9 @@ pub fn deinit() void { } // keyboard settings: - const keyboard = JsonElement.initObject(main.globalAllocator); + const keyboard = JsonElement.initObject(main.stackAllocator); for(&main.KeyBoard.keys) |key| { - const keyJson = JsonElement.initObject(main.globalAllocator); + const keyJson = JsonElement.initObject(main.stackAllocator); keyJson.put("key", key.key); keyJson.put("mouseButton", key.mouseButton); keyJson.put("scancode", key.scancode); diff --git a/src/utils.zig b/src/utils.zig index 5c3f1147..1af33716 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -8,7 +8,7 @@ const main = @import("main.zig"); pub const Compression = struct { pub fn deflate(allocator: NeverFailingAllocator, data: []const u8) []u8 { var result = main.List(u8).init(allocator); - var comp = std.compress.deflate.compressor(main.globalAllocator.allocator, result.writer(), .{.level = .default_compression}) catch unreachable; + var comp = std.compress.deflate.compressor(main.stackAllocator.allocator, result.writer(), .{.level = .default_compression}) catch unreachable; _ = comp.write(data) catch unreachable; comp.close() catch unreachable; comp.deinit(); @@ -25,9 +25,9 @@ pub const Compression = struct { } pub fn pack(sourceDir: std.fs.Dir, writer: anytype) !void { - var comp = try std.compress.deflate.compressor(main.globalAllocator.allocator, writer, .{.level = .default_compression}); + var comp = try std.compress.deflate.compressor(main.stackAllocator.allocator, writer, .{.level = .default_compression}); defer comp.deinit(); - var walker = try sourceDir.walk(main.globalAllocator.allocator); + var walker = try sourceDir.walk(main.stackAllocator.allocator); defer walker.deinit(); while(try walker.next()) |entry| { @@ -61,7 +61,7 @@ pub const Compression = struct { pub fn unpack(outDir: std.fs.Dir, input: []const u8) !void { var stream = std.io.fixedBufferStream(input); - var decomp = try std.compress.deflate.decompressor(main.globalAllocator.allocator, stream.reader(), null); + var decomp = try std.compress.deflate.decompressor(main.stackAllocator.allocator, stream.reader(), null); defer decomp.deinit(); const reader = decomp.reader(); const _data = try reader.readAllAlloc(main.stackAllocator.allocator, std.math.maxInt(usize)); @@ -373,26 +373,23 @@ pub fn CircularBufferQueue(comptime T: type) type { /// Allows for stack-like allocations in a fast and safe way. /// It is safe in the sense that a regular allocator will be used when the buffer is full. pub const StackAllocator = struct { - const Allocation = struct{start: u32, len: u32}; + const AllocationTrailer = packed struct{wasFreed: bool, previousAllocationTrailer: u31}; backingAllocator: NeverFailingAllocator, buffer: []align(4096) u8, - allocationList: main.List(Allocation), index: usize, - pub fn init(backingAllocator: NeverFailingAllocator, size: u32) StackAllocator { + pub fn init(backingAllocator: NeverFailingAllocator, size: u31) StackAllocator { return .{ .backingAllocator = backingAllocator, .buffer = backingAllocator.alignedAlloc(u8, 4096, size), - .allocationList = main.List(Allocation).init(backingAllocator), .index = 0, }; } pub fn deinit(self: StackAllocator) void { - if(self.allocationList.items.len != 0) { + if(self.index != 0) { std.log.err("Memory leak in Stack Allocator", .{}); } - self.allocationList.deinit(); self.backingAllocator.free(self.buffer); } @@ -423,6 +420,16 @@ pub const StackAllocator = struct { return compare - bufferStart; } + fn getTrueAllocationEnd(start: usize, len: usize) usize { + const trailerStart = std.mem.alignForward(usize, start + len, @alignOf(AllocationTrailer)); + return trailerStart + @sizeOf(AllocationTrailer); + } + + fn getTrailerBefore(self: *StackAllocator, end: usize) *AllocationTrailer { + const trailerStart = end - @sizeOf(AllocationTrailer); + return @ptrCast(@alignCast(self.buffer[trailerStart..].ptr)); + } + /// Attempt to allocate exactly `len` bytes aligned to `1 << ptr_align`. /// /// `ret_addr` is optionally provided as the first return address of the @@ -430,11 +437,12 @@ pub const StackAllocator = struct { /// has been provided. fn alloc(ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 { const self: *StackAllocator = @ptrCast(@alignCast(ctx)); - if(len >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr); const start = std.mem.alignForward(usize, self.index, @as(usize, 1) << @intCast(ptr_align)); - if(start + len >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr); - self.allocationList.append(.{.start = @intCast(start), .len = @intCast(len)}); - self.index = start + len; + const end = getTrueAllocationEnd(start, len); + if(end >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr); + const trailer = self.getTrailerBefore(end); + trailer.* = .{.wasFreed = false, .previousAllocationTrailer = @intCast(self.index)}; + self.index = end; return self.buffer.ptr + start; } @@ -456,16 +464,18 @@ pub const StackAllocator = struct { fn resize(ctx: *anyopaque, buf: []u8, buf_align: u8, new_len: usize, ret_addr: usize) bool { const self: *StackAllocator = @ptrCast(@alignCast(ctx)); if(self.isInsideBuffer(buf)) { - const top = &self.allocationList.items[self.allocationList.items.len - 1]; - std.debug.assert(top.start == self.indexInBuffer(buf)); // Can only resize the top element. - std.debug.assert(top.len == buf.len); - std.debug.assert(self.index >= top.start + top.len); - if(top.start + new_len >= self.buffer.len) { - return false; - } - self.index -= top.len; - self.index += new_len; - top.len = @intCast(new_len); + const start = self.indexInBuffer(buf); + const end = getTrueAllocationEnd(start, buf.len); + if(end != self.index) return false; + const newEnd = getTrueAllocationEnd(start, new_len); + if(newEnd >= self.buffer.len) return false; + + const trailer = self.getTrailerBefore(end); + std.debug.assert(!trailer.wasFreed); + const newTrailer = self.getTrailerBefore(newEnd); + + newTrailer.* = .{.wasFreed = false, .previousAllocationTrailer = trailer.previousAllocationTrailer}; + self.index = newEnd; return true; } else { return self.backingAllocator.rawResize(buf, buf_align, new_len, ret_addr); @@ -486,11 +496,24 @@ pub const StackAllocator = struct { fn free(ctx: *anyopaque, buf: []u8, buf_align: u8, ret_addr: usize) void { const self: *StackAllocator = @ptrCast(@alignCast(ctx)); if(self.isInsideBuffer(buf)) { - const top = self.allocationList.pop(); - std.debug.assert(top.start == self.indexInBuffer(buf)); // Can only free the top element. - std.debug.assert(top.len == buf.len); - std.debug.assert(self.index >= top.start + top.len); - self.index = top.start; + const start = self.indexInBuffer(buf); + const end = getTrueAllocationEnd(start, buf.len); + const trailer = self.getTrailerBefore(end); + std.debug.assert(!trailer.wasFreed); // Double Free + + if(end == self.index) { + self.index = trailer.previousAllocationTrailer; + if(self.index != 0) { + var previousTrailer = self.getTrailerBefore(trailer.previousAllocationTrailer); + while(previousTrailer.wasFreed) { + self.index = previousTrailer.previousAllocationTrailer; + if(self.index == 0) break; + previousTrailer = self.getTrailerBefore(previousTrailer.previousAllocationTrailer); + } + } + } else { + trailer.wasFreed = true; + } } else { self.backingAllocator.rawFree(buf, buf_align, ret_addr); }