diff --git a/build.zig b/build.zig index 910f31d..7bc8960 100644 --- a/build.zig +++ b/build.zig @@ -25,10 +25,6 @@ pub fn build(b: *std.Build) void { .link_libc = true, }); rendering.addIncludePath(b.path("ext")); - if (target.result.os.tag == .macos) { - rendering.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" }); - rendering.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" }); - } rendering.addCSourceFile(.{ .file = b.path("ext/stb_image.c") }); rendering.addImport("math", math); @@ -49,12 +45,8 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }), }); - sideros.root_module.addIncludePath(b.path("ext")); - sideros.root_module.addIncludePath(b.path("src")); - if (target.result.os.tag == .macos) { - sideros.root_module.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" }); - sideros.root_module.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" }); - } + sideros.addIncludePath(b.path("ext")); + sideros.addIncludePath(b.path("src")); sideros.root_module.addImport("mods", mods); sideros.root_module.addImport("ecs", ecs); @@ -79,18 +71,18 @@ pub fn build(b: *std.Build) void { }), }); exe.root_module.addIncludePath(b.path("src")); - exe.root_module.linkLibrary(sideros); - exe.root_module.link_libc = true; - exe.root_module.linkSystemLibrary("vulkan", .{ .needed = true }); + exe.linkLibrary(sideros); + exe.linkLibC(); + exe.linkSystemLibrary("vulkan"); if (wayland) { exe.root_module.addIncludePath(b.path("ext")); - exe.root_module.linkSystemLibrary("wayland-client", .{}); - exe.root_module.linkSystemLibrary("xkbcommon", .{}); + exe.linkSystemLibrary("wayland-client"); + exe.linkSystemLibrary("xkbcommon"); exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") }); } else { - exe.root_module.linkSystemLibrary("xcb", .{}); - exe.root_module.linkSystemLibrary("xcb-keysyms", .{}); - exe.root_module.linkSystemLibrary("xcb-icccm", .{}); + exe.linkSystemLibrary("xcb"); + exe.linkSystemLibrary("xcb-keysyms"); + exe.linkSystemLibrary("xcb-icccm"); } b.installArtifact(exe); @@ -114,14 +106,14 @@ pub fn build(b: *std.Build) void { }), }); exe.root_module.addIncludePath(b.path("src")); - exe.root_module.linkSystemLibrary("vulkan", .{}); + exe.linkSystemLibrary("vulkan"); exe.root_module.addSystemIncludePath(.{ .cwd_relative = "/usr/local/include" }); exe.root_module.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" }); exe.root_module.addCSourceFile(.{.file = b.path("src/window.m")}); exe.root_module.linkFramework("Cocoa", .{}); exe.root_module.linkFramework("Metal", .{}); exe.root_module.linkFramework("QuartzCore", .{}); - exe.root_module.linkLibrary(sideros); + exe.linkLibrary(sideros); b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); @@ -164,10 +156,13 @@ pub fn build(b: *std.Build) void { } fn compileAllShaders(b: *std.Build, module: *std.Build.Module) void { - const shaders_dir = b.build_root.handle.openDir(b.graph.io, "assets/shaders", .{ .iterate = true }) catch @panic("Failed to open shaders directory"); + const shaders_dir = if (@hasDecl(@TypeOf(b.build_root.handle), "openIterableDir")) + b.build_root.handle.openIterableDir("assets/shaders", .{}) catch @panic("Failed to open shaders directory") + else + b.build_root.handle.openDir("assets/shaders", .{ .iterate = true }) catch @panic("Failed to open shaders directory"); var file_it = shaders_dir.iterate(); - while (file_it.next(b.graph.io) catch @panic("Failed to iterate shader directory")) |entry| { + while (file_it.next() catch @panic("Failed to iterate shader directory")) |entry| { if (entry.kind == .file) { const ext = std.fs.path.extension(entry.name); const basename = std.fs.path.basename(entry.name); diff --git a/src/ecs/entities.zig b/src/ecs/entities.zig index bb1c841..6f8f2b3 100644 --- a/src/ecs/entities.zig +++ b/src/ecs/entities.zig @@ -33,20 +33,27 @@ pub const Pool = struct { allocator: Allocator, system_groups: std.ArrayList(SystemGroup), sync_groups: std.ArrayList(SyncGroup), - threaded_io: std.Io.Threaded, + thread_pool: *std.Thread.Pool, + wait_group: std.Thread.WaitGroup, + mutex: std.Thread.Mutex, pub fn init(allocator: Allocator, resources: *Resources) !@This() { - const pool = @This(){ + var pool = @This(){ .humans = .{}, .resources = resources, .system_groups = std.ArrayList(SystemGroup).empty, .sync_groups = std.ArrayList(SystemGroup).empty, - .threaded_io = .init(allocator, .{ - .concurrent_limit = .limited(4), - }), + .thread_pool = try allocator.create(std.Thread.Pool), + .wait_group = .{}, + .mutex = .{}, .allocator = allocator, }; + try pool.thread_pool.init(.{ + .allocator = allocator, + .n_jobs = 4, + }); + return pool; } @@ -63,37 +70,28 @@ pub const Pool = struct { self.system_groups.deinit(self.allocator); self.sync_groups.deinit(self.allocator); - self.threaded_io.deinit(); + self.thread_pool.deinit(); + self.allocator.destroy(self.thread_pool); } pub fn tick(self: *@This()) void { - const io = self.threaded_io.io(); - var group: std.Io.Group = .init; - for (0..self.system_groups.items.len) |i| { - group.concurrent(io, struct { - fn run(pool: *Pool, index: usize) std.Io.Cancelable!void { - const system_group = pool.system_groups.items[index]; - for (system_group) |system| { + self.thread_pool.spawnWg(&self.wait_group, struct { + fn run(pool: *Pool, index: usize) void { + const group = pool.system_groups.items[index]; + for (group) |system| { // TODO: system errors should be correctly handled system(pool) catch unreachable; } } - }.run, .{ self, i }) catch { - const system_group = self.system_groups.items[i]; - for (system_group) |system| { - system(self) catch unreachable; - } - }; + }.run, .{ self, i }); } for (0..self.sync_groups.items.len) |i| { - const system_group = self.sync_groups.items[i]; - for (system_group) |system| { + const group = self.sync_groups.items[i]; + for (group) |system| { system(self) catch unreachable; } } - - group.await(io) catch unreachable; } fn getEntities(self: *@This(), T: type) *std.MultiArrayList(T) { diff --git a/src/macos.zig b/src/macos.zig index e802ec6..59322db 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -149,18 +149,18 @@ fn vulkan_cleanup(gameInit: sideros.GameInit) void { //c.vkDestroyInstance(gameInit.instance, null); } -pub fn main(init: std.process.Init) !void { +pub fn main() !void { create_window(); const layer = get_metal_layer(); - var gpa: std.heap.DebugAllocator(.{}) = .init; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); defer if (gpa.deinit() != .ok) @panic("Memory leaked"); const gameInit = try vulkan_init(allocator, layer); defer vulkan_cleanup(gameInit); - sideros.sideros_init(init.io, gameInit); + sideros.sideros_init(gameInit); while (!is_window_closed()) { poll_cocoa_events(); diff --git a/src/mods/ir.zig b/src/mods/ir.zig index 45eedde..2dcd8a7 100644 --- a/src/mods/ir.zig +++ b/src/mods/ir.zig @@ -27,9 +27,12 @@ const DIndex = packed struct { x: u32, y: u32, }; - -/// This intentionally remains tagless; the opcode determines how to interpret it. -const Index = union { +comptime { + // TODO: is this too big? we could do with 32 bits and a bit more indirection + std.debug.assert(@sizeOf(Index) == 8); +} +/// packed union has no tag +const Index = packed union { u32: u32, i32: i32, u64: u64, diff --git a/src/rendering/GraphicsPipeline.zig b/src/rendering/GraphicsPipeline.zig index 7224515..ae43342 100644 --- a/src/rendering/GraphicsPipeline.zig +++ b/src/rendering/GraphicsPipeline.zig @@ -61,8 +61,8 @@ pub const Builder = struct { }; } - pub fn addMesh(self: *Builder, io: std.Io, path: []const u8) !Mesh { - const gltf_data = try gltf.parseFile(self.allocator, io, path); + pub fn addMesh(self: *Builder, path: []const u8) !Mesh { + const gltf_data = try gltf.parseFile(self.allocator, path); const vertex_buffer = try createVertexBuffer(self.allocator, self.device, gltf_data); const index_buffer = try createIndexBuffer(self.allocator, self.device, gltf_data); diff --git a/src/rendering/Renderer.zig b/src/rendering/Renderer.zig index ed6d1f6..fe9dd7c 100644 --- a/src/rendering/Renderer.zig +++ b/src/rendering/Renderer.zig @@ -20,10 +20,10 @@ terrain_pipeline: vk.TerrainPipeline, current_frame: u32, mesh: Mesh, transforms: std.ArrayList(math.Transform), -previous_time: std.Io.Timestamp, +previous_time: std.time.Instant, current_image: usize, -pub fn init(allocator: Allocator, io: std.Io, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self { +pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self { const instance: vk.Instance = .{ .handle = instance_handle }; const surface: vk.Surface = .{ .handle = surface_handle }; var physical_device = try vk.PhysicalDevice.pick(allocator, instance); @@ -48,7 +48,7 @@ pub fn init(allocator: Allocator, io: std.Io, instance_handle: vk.c.VkInstance, _ = try pipeline_builder.addTexture(texture, diffuse); _ = try pipeline_builder.addTexture(texture, diffuse); - const mesh = try pipeline_builder.addMesh(io, "assets/models/cube.glb"); + const mesh = try pipeline_builder.addMesh("assets/models/cube.glb"); var graphics_pipeline = try pipeline_builder.build(swapchain, render_pass, vertex_shader, fragment_shader); const terrain_vertex_shader = try device.initShader("terrain_vert"); @@ -96,7 +96,7 @@ pub fn init(allocator: Allocator, io: std.Io, instance_handle: vk.c.VkInstance, .terrain_pipeline = terrain_pipeline, .current_frame = 0, .transforms = transforms, - .previous_time = std.Io.Timestamp.now(std.Io.Threaded.global_single_threaded.io(), .awake), + .previous_time = try std.time.Instant.now(), .mesh = mesh, .current_image = undefined, }; diff --git a/src/rendering/gltf.zig b/src/rendering/gltf.zig index 7a3971c..7073695 100644 --- a/src/rendering/gltf.zig +++ b/src/rendering/gltf.zig @@ -161,8 +161,8 @@ pub const Model = struct { }; }; -pub fn parseFile(allocator: Allocator, io: std.Io, name: []const u8) !struct { vertices: [][3]f32, normals: [][3]f32, uvs: [][2]f32, indices: []u16 } { - const file = try std.Io.Dir.cwd().openFile(name, io, .{}); +pub fn parseFile(allocator: Allocator, name: []const u8) !struct { vertices: [][3]f32, normals: [][3]f32, uvs: [][2]f32, indices: []u16 } { + const file = try std.fs.cwd().openFile(name, .{}); const all = try file.readToEndAlloc(allocator, 1_000_000); defer allocator.free(all); const json_chunk = std.mem.bytesAsValue(Model.Chunk, all[Model.Header.offset..]); diff --git a/src/sideros.zig b/src/sideros.zig index 08dc809..cf016fe 100644 --- a/src/sideros.zig +++ b/src/sideros.zig @@ -12,7 +12,7 @@ const std = @import("std"); const systems = @import("systems.zig"); -var gpa: std.heap.DebugAllocator(.{}) = .{}; +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); var pool: ecs.Pool = undefined; var renderer: Renderer = undefined; @@ -26,7 +26,7 @@ const ModInfo = struct { runtime: *mods.Runtime, modIdx: u32, }; -var loadedMods: std.ArrayListUnmanaged(ModInfo) = .empty; +var loadedMods: std.ArrayListUnmanaged(ModInfo) = .{}; fn openOrCreateDir(fs: std.fs.Dir, path: []const u8) !std.fs.Dir { var dir: std.fs.Dir = undefined; @@ -133,7 +133,7 @@ fn init_mods() void { } } -fn sideros_init(io: std.Io, init: api.GameInit) void { +export fn sideros_init(init: api.GameInit) callconv(.c) void { resources = .{ .camera = &camera, .renderer = undefined, @@ -145,7 +145,7 @@ fn sideros_init(io: std.Io, init: api.GameInit) void { ecs.hooks.addHook(.scroll, systems.zoomCamera) catch @panic("TODO handle this"); pool = ecs.Pool.init(allocator, &resources) catch @panic("TODO: Gracefully handle error"); // TODO(ernesto): I think this @ptrCast are unavoidable but maybe not? - renderer = Renderer.init(allocator, io, @ptrCast(init.instance), @ptrCast(init.surface)) catch |err| std.debug.panic("TODO: Gracefully handle error: {}\n", .{err}); + renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch |err| std.debug.panic("TODO: Gracefully handle error: {}\n", .{err}); resources.terrain = rendering.Terrain.init(allocator, renderer.device, .{ .octaves = 8, diff --git a/src/systems.zig b/src/systems.zig index 1b5c1b0..8b708f4 100644 --- a/src/systems.zig +++ b/src/systems.zig @@ -8,8 +8,8 @@ pub fn render(pool: *ecs.Pool) anyerror!void { const camera = pool.resources.camera; const terrain = pool.resources.terrain; - const now = std.Io.Timestamp.now(pool.threaded_io.io(), .awake); - const delta_time: f32 = @as(f32, @floatFromInt(renderer.previous_time.durationTo(now).toNanoseconds())) / @as(f32, 1_000_000_000.0); + const now = try std.time.Instant.now(); + const delta_time: f32 = @as(f32, @floatFromInt(now.since(renderer.previous_time))) / @as(f32, 1_000_000_000.0); pool.resources.delta_time = delta_time; renderer.previous_time = now;