first steps towards porting to 0.16

This commit is contained in:
Lorenzo Torres 2026-04-17 13:54:38 +02:00
parent e1b960da37
commit e99779fcbc
9 changed files with 65 additions and 61 deletions

View file

@ -25,6 +25,10 @@ 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);
@ -45,8 +49,12 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
}),
});
sideros.addIncludePath(b.path("ext"));
sideros.addIncludePath(b.path("src"));
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.root_module.addImport("mods", mods);
sideros.root_module.addImport("ecs", ecs);
@ -71,18 +79,18 @@ pub fn build(b: *std.Build) void {
}),
});
exe.root_module.addIncludePath(b.path("src"));
exe.linkLibrary(sideros);
exe.linkLibC();
exe.linkSystemLibrary("vulkan");
exe.root_module.linkLibrary(sideros);
exe.root_module.link_libc = true;
exe.root_module.linkSystemLibrary("vulkan", .{ .needed = true });
if (wayland) {
exe.root_module.addIncludePath(b.path("ext"));
exe.linkSystemLibrary("wayland-client");
exe.linkSystemLibrary("xkbcommon");
exe.root_module.linkSystemLibrary("wayland-client", .{});
exe.root_module.linkSystemLibrary("xkbcommon", .{});
exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") });
} else {
exe.linkSystemLibrary("xcb");
exe.linkSystemLibrary("xcb-keysyms");
exe.linkSystemLibrary("xcb-icccm");
exe.root_module.linkSystemLibrary("xcb", .{});
exe.root_module.linkSystemLibrary("xcb-keysyms", .{});
exe.root_module.linkSystemLibrary("xcb-icccm", .{});
}
b.installArtifact(exe);
@ -106,14 +114,14 @@ pub fn build(b: *std.Build) void {
}),
});
exe.root_module.addIncludePath(b.path("src"));
exe.linkSystemLibrary("vulkan");
exe.root_module.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.linkLibrary(sideros);
exe.root_module.linkLibrary(sideros);
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
@ -156,13 +164,10 @@ pub fn build(b: *std.Build) void {
}
fn compileAllShaders(b: *std.Build, module: *std.Build.Module) void {
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");
const shaders_dir = b.build_root.handle.openDir(b.graph.io, "assets/shaders", .{ .iterate = true }) catch @panic("Failed to open shaders directory");
var file_it = shaders_dir.iterate();
while (file_it.next() catch @panic("Failed to iterate shader directory")) |entry| {
while (file_it.next(b.graph.io) 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);

View file

@ -33,27 +33,20 @@ pub const Pool = struct {
allocator: Allocator,
system_groups: std.ArrayList(SystemGroup),
sync_groups: std.ArrayList(SyncGroup),
thread_pool: *std.Thread.Pool,
wait_group: std.Thread.WaitGroup,
mutex: std.Thread.Mutex,
threaded_io: std.Io.Threaded,
pub fn init(allocator: Allocator, resources: *Resources) !@This() {
var pool = @This(){
const pool = @This(){
.humans = .{},
.resources = resources,
.system_groups = std.ArrayList(SystemGroup).empty,
.sync_groups = std.ArrayList(SystemGroup).empty,
.thread_pool = try allocator.create(std.Thread.Pool),
.wait_group = .{},
.mutex = .{},
.threaded_io = .init(allocator, .{
.concurrent_limit = .limited(4),
}),
.allocator = allocator,
};
try pool.thread_pool.init(.{
.allocator = allocator,
.n_jobs = 4,
});
return pool;
}
@ -70,28 +63,37 @@ pub const Pool = struct {
self.system_groups.deinit(self.allocator);
self.sync_groups.deinit(self.allocator);
self.thread_pool.deinit();
self.allocator.destroy(self.thread_pool);
self.threaded_io.deinit();
}
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| {
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| {
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| {
// TODO: system errors should be correctly handled
system(pool) catch unreachable;
}
}
}.run, .{ self, i });
}.run, .{ self, i }) catch {
const system_group = self.system_groups.items[i];
for (system_group) |system| {
system(self) catch unreachable;
}
};
}
for (0..self.sync_groups.items.len) |i| {
const group = self.sync_groups.items[i];
for (group) |system| {
const system_group = self.sync_groups.items[i];
for (system_group) |system| {
system(self) catch unreachable;
}
}
group.await(io) catch unreachable;
}
fn getEntities(self: *@This(), T: type) *std.MultiArrayList(T) {

View file

@ -149,18 +149,18 @@ fn vulkan_cleanup(gameInit: sideros.GameInit) void {
//c.vkDestroyInstance(gameInit.instance, null);
}
pub fn main() !void {
pub fn main(init: std.process.Init) !void {
create_window();
const layer = get_metal_layer();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var gpa: std.heap.DebugAllocator(.{}) = .init;
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(gameInit);
sideros.sideros_init(init.io, gameInit);
while (!is_window_closed()) {
poll_cocoa_events();

View file

@ -27,12 +27,9 @@ const DIndex = packed struct {
x: u32,
y: u32,
};
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 {
/// This intentionally remains tagless; the opcode determines how to interpret it.
const Index = union {
u32: u32,
i32: i32,
u64: u64,

View file

@ -61,8 +61,8 @@ pub const Builder = struct {
};
}
pub fn addMesh(self: *Builder, path: []const u8) !Mesh {
const gltf_data = try gltf.parseFile(self.allocator, path);
pub fn addMesh(self: *Builder, io: std.Io, path: []const u8) !Mesh {
const gltf_data = try gltf.parseFile(self.allocator, io, path);
const vertex_buffer = try createVertexBuffer(self.allocator, self.device, gltf_data);
const index_buffer = try createIndexBuffer(self.allocator, self.device, gltf_data);

View file

@ -20,10 +20,10 @@ terrain_pipeline: vk.TerrainPipeline,
current_frame: u32,
mesh: Mesh,
transforms: std.ArrayList(math.Transform),
previous_time: std.time.Instant,
previous_time: std.Io.Timestamp,
current_image: usize,
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self {
pub fn init(allocator: Allocator, io: std.Io, 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, instance_handle: vk.c.VkInstance, surface_hand
_ = try pipeline_builder.addTexture(texture, diffuse);
_ = try pipeline_builder.addTexture(texture, diffuse);
const mesh = try pipeline_builder.addMesh("assets/models/cube.glb");
const mesh = try pipeline_builder.addMesh(io, "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, instance_handle: vk.c.VkInstance, surface_hand
.terrain_pipeline = terrain_pipeline,
.current_frame = 0,
.transforms = transforms,
.previous_time = try std.time.Instant.now(),
.previous_time = std.Io.Timestamp.now(std.Io.Threaded.global_single_threaded.io(), .awake),
.mesh = mesh,
.current_image = undefined,
};

View file

@ -161,8 +161,8 @@ pub const Model = struct {
};
};
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, .{});
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, .{});
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..]);

View file

@ -12,7 +12,7 @@ const std = @import("std");
const systems = @import("systems.zig");
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var gpa: std.heap.DebugAllocator(.{}) = .{};
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) = .{};
var loadedMods: std.ArrayListUnmanaged(ModInfo) = .empty;
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 {
}
}
export fn sideros_init(init: api.GameInit) callconv(.c) void {
fn sideros_init(io: std.Io, init: api.GameInit) void {
resources = .{
.camera = &camera,
.renderer = undefined,
@ -145,7 +145,7 @@ export fn sideros_init(init: api.GameInit) callconv(.c) 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, @ptrCast(init.instance), @ptrCast(init.surface)) catch |err| std.debug.panic("TODO: Gracefully handle error: {}\n", .{err});
renderer = Renderer.init(allocator, io, @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,

View file

@ -8,8 +8,8 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
const camera = pool.resources.camera;
const terrain = pool.resources.terrain;
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);
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);
pool.resources.delta_time = delta_time;
renderer.previous_time = now;