Add support for launch args and "dump_shader_translations" arg #59

Merged
kayomn merged 1 commits from launch_args into main 2024-07-22 22:29:47 +02:00
7 changed files with 141 additions and 109 deletions

View File

@ -30,12 +30,10 @@ const Player = struct {
move_y: ona.act.Axis = .{.keys = .{.w, .s}}, move_y: ona.act.Axis = .{.keys = .{.w, .s}},
}; };
pub fn main() !void { pub const main = ona.start(setup, .{
try ona.start_app(setup, .{ .tick_rate = 60,
.tick_rate = 60, .execution = .{.thread_share = 0.1},
.execution = .{.thread_share = 0.1}, });
});
}
fn load(config: ona.Write(ona.gfx.Config), actors: ona.Write(Actors), assets: ona.Write(ona.gfx.Assets)) !void { fn load(config: ona.Write(ona.gfx.Config), actors: ona.Write(Actors), assets: ona.Write(ona.gfx.Assets)) !void {
config.res.width, config.res.height = .{1280, 720}; config.res.width, config.res.height = .{1280, 720};

View File

@ -1,25 +0,0 @@
const coral = @import("coral");
const flow = @import("flow");
events: *const Events,
target_frame_time: f64,
elapsed_time: f64,
is_running: bool,
pub const Events = struct {
load: flow.World.Event,
pre_update: flow.World.Event,
update: flow.World.Event,
post_update: flow.World.Event,
render: flow.World.Event,
finish: flow.World.Event,
exit: flow.World.Event,
};
const Self = @This();
pub fn quit(self: *Self) void {
self.is_running = false;
}

View File

@ -1,17 +1,13 @@
const App = @import("./App.zig");
const coral = @import("coral"); const coral = @import("coral");
const flow = @import("flow"); const flow = @import("flow");
const gfx = @import("./gfx.zig"); const ona = @import("./ona.zig");
const msg = @import("./msg.zig");
const std = @import("std"); const std = @import("std");
pub const Axis = struct { pub const Axis = struct {
keys: ?[2]gfx.Input.Key = null, keys: ?[2]ona.gfx.Input.Key = null,
}; };
pub const Mapping = struct { pub const Mapping = struct {
@ -37,7 +33,7 @@ pub const Mapping = struct {
} }
}; };
pub fn setup(world: *flow.World, events: App.Events) std.mem.Allocator.Error!void { pub fn setup(world: *flow.World, events: ona.App.Events) std.mem.Allocator.Error!void {
try world.set_state(Mapping{}); try world.set_state(Mapping{});
try world.on_event(events.pre_update, flow.system_fn(update), .{ try world.on_event(events.pre_update, flow.system_fn(update), .{
@ -45,7 +41,7 @@ pub fn setup(world: *flow.World, events: App.Events) std.mem.Allocator.Error!voi
}); });
} }
pub fn update(inputs: msg.Receive(gfx.Input), mapping: flow.Write(Mapping)) void { pub fn update(inputs: ona.msg.Receive(ona.gfx.Input), mapping: flow.Write(Mapping)) void {
mapping.res.keys_pressed = Mapping.ScancodeSet.initEmpty(); mapping.res.keys_pressed = Mapping.ScancodeSet.initEmpty();
for (inputs.messages()) |message| { for (inputs.messages()) |message| {

View File

@ -1,5 +1,3 @@
const App = @import("./App.zig");
pub const colors = @import("./gfx/colors.zig"); pub const colors = @import("./gfx/colors.zig");
const coral = @import("coral"); const coral = @import("coral");
@ -8,7 +6,7 @@ const ext = @import("./ext.zig");
const flow = @import("flow"); const flow = @import("flow");
const msg = @import("./msg.zig"); const ona = @import("./ona.zig");
const rendering = @import("./gfx/rendering.zig"); const rendering = @import("./gfx/rendering.zig");
@ -437,7 +435,7 @@ fn load_bmp_texture(arena: *std.heap.ArenaAllocator, storage: coral.files.Storag
}; };
} }
pub fn poll(app: flow.Write(App), inputs: msg.Send(Input)) !void { pub fn poll(app: flow.Write(ona.App), inputs: ona.msg.Send(Input)) !void {
var event = @as(ext.SDL_Event, undefined); var event = @as(ext.SDL_Event, undefined);
while (ext.SDL_PollEvent(&event) != 0) { while (ext.SDL_PollEvent(&event) != 0) {
@ -450,7 +448,7 @@ pub fn poll(app: flow.Write(App), inputs: msg.Send(Input)) !void {
} }
} }
pub fn setup(world: *flow.World, events: App.Events) (error {Unsupported} || std.Thread.SpawnError || std.mem.Allocator.Error)!void { pub fn setup(world: *flow.World, events: ona.App.Events) (error {Unsupported} || std.Thread.SpawnError || std.mem.Allocator.Error)!void {
if (ext.SDL_Init(ext.SDL_INIT_VIDEO) != 0) { if (ext.SDL_Init(ext.SDL_INIT_VIDEO) != 0) {
return error.Unsupported; return error.Unsupported;
} }

View File

@ -4,6 +4,8 @@ const ext = @cImport({
@cInclude("spirv-cross/spirv_cross_c.h"); @cInclude("spirv-cross/spirv_cross_c.h");
}); });
const ona = @import("../ona.zig");
const std = @import("std"); const std = @import("std");
pub const Error = std.mem.Allocator.Error || error { pub const Error = std.mem.Allocator.Error || error {
@ -283,7 +285,9 @@ pub fn analyze(arena: *std.heap.ArenaAllocator, options: Options) Error!Program
try stage.reflect_images_samplers(arena, compiler, resources); try stage.reflect_images_samplers(arena, compiler, resources);
try stage.reflect_uniform_blocks(arena, compiler, resources); try stage.reflect_uniform_blocks(arena, compiler, resources);
std.log.info("{s}", .{stage.source}); if (ona.launch_arg(.dump_shader_translations) != null) {
std.log.info("Vertex translated:\n{s}", .{stage.source});
}
break: vertex_stage stage; break: vertex_stage stage;
}, },
@ -307,7 +311,9 @@ pub fn analyze(arena: *std.heap.ArenaAllocator, options: Options) Error!Program
try stage.reflect_images_samplers(arena, compiler, resources); try stage.reflect_images_samplers(arena, compiler, resources);
try stage.reflect_uniform_blocks(arena, compiler, resources); try stage.reflect_uniform_blocks(arena, compiler, resources);
std.log.info("{s}", .{stage.source}); if (ona.launch_arg(.dump_shader_translations) != null) {
std.log.info("Fragment translated:\n{s}", .{stage.source});
}
break: fragment_stage stage; break: fragment_stage stage;
}, },

View File

@ -1,9 +1,9 @@
const App = @import("./App.zig");
const coral = @import("coral"); const coral = @import("coral");
const flow = @import("flow"); const flow = @import("flow");
const ona = @import("./ona.zig");
const std = @import("std"); const std = @import("std");
fn Channel(comptime Message: type) type { fn Channel(comptime Message: type) type {
@ -106,7 +106,7 @@ pub fn Send(comptime Message: type) type {
.channel = (try context.register_writable_state_access(TypedChannel)) orelse set: { .channel = (try context.register_writable_state_access(TypedChannel)) orelse set: {
try context.world.set_state(TypedChannel.init(coral.heap.allocator)); try context.world.set_state(TypedChannel.init(coral.heap.allocator));
const app = context.world.get_state(App).?; const app = context.world.get_state(ona.App).?;
try context.world.on_event(app.events.post_update, flow.system_fn(TypedChannel.swap), .{ try context.world.on_event(app.events.post_update, flow.system_fn(TypedChannel.swap), .{
.label = "swap channel of " ++ @typeName(Message), .label = "swap channel of " ++ @typeName(Message),

View File

@ -1,5 +1,3 @@
pub const App = @import("./App.zig");
pub const act = @import("./act.zig"); pub const act = @import("./act.zig");
const coral = @import("coral"); const coral = @import("coral");
@ -14,6 +12,35 @@ pub const msg = @import("./msg.zig");
const std = @import("std"); const std = @import("std");
pub const App = struct {
events: *const Events,
target_frame_time: f64,
elapsed_time: f64,
is_running: bool,
pub const Events = struct {
load: flow.World.Event,
pre_update: flow.World.Event,
update: flow.World.Event,
post_update: flow.World.Event,
render: flow.World.Event,
finish: flow.World.Event,
exit: flow.World.Event,
};
pub fn quit(self: *App) void {
self.is_running = false;
}
};
pub const Flag = enum {
dump_shader_translations,
var launch_args = [_]?[]const u8{null} ** std.enums.values(Flag).len;
const values = std.enums.values(Flag);
};
pub const Options = struct { pub const Options = struct {
tick_rate: u64, tick_rate: u64,
execution: Execution, execution: Execution,
@ -38,79 +65,111 @@ pub const default_middlewares = &.{
act.setup, act.setup,
}; };
pub fn start_app(setup: Setup, options: Options) anyerror!void { pub fn launch_arg(flag: Flag) ?[]const u8 {
defer { return Flag.launch_args[@intFromEnum(flag)];
coral.heap.trace_leaks(); }
ext.SDL_Quit();
}
var world = try switch (options.execution) { pub fn start(comptime setup: Setup, options: Options) fn () anyerror!void {
.single_threaded => flow.World.init(0), const Start = struct {
fn main() anyerror!void {
defer {
coral.heap.trace_leaks();
ext.SDL_Quit();
}
.thread_share => |thread_share| init: { parse_args: for (std.os.argv[1 ..]) |arg| {
const cpu_count = @as(u32, @intCast(std.math.clamp(std.Thread.getCpuCount() catch |cpu_count_error| { const arg_span = std.mem.span(arg);
@panic(switch (cpu_count_error) { const arg_split_index = std.mem.indexOfScalar(u8, arg_span, '=') orelse arg_span.len;
error.PermissionDenied => "permission denied retrieving CPU count", const arg_name = arg_span[0 .. arg_split_index];
error.SystemResources => "system resources are preventing retrieval of the CPU count",
error.Unexpected => "unexpected failure retrieving CPU count",
});
}, 0, std.math.maxInt(u32))));
break: init flow.World.init(coral.scalars.fractional(cpu_count, thread_share) orelse 0); for (Flag.values) |value| {
}, const name = @tagName(value);
};
defer world.deinit(); if (!std.mem.eql(u8, arg_name, name)) {
continue;
}
const events = App.Events{ Flag.launch_args[@intFromEnum(value)] =
.load = try world.create_event("load"), if (arg_split_index == arg_span.len)
.pre_update = try world.create_event("pre-update"), name
.update = try world.create_event("update"), else
.post_update = try world.create_event("post-update"), arg_span[arg_split_index ..];
.render = try world.create_event("render"),
.finish = try world.create_event("finish"),
.exit = try world.create_event("exit"),
};
const app = try world.set_get_state(App{ continue: parse_args;
.events = &events, }
.target_frame_time = 1.0 / @as(f64, @floatFromInt(options.tick_rate)), }
.elapsed_time = 0,
.is_running = true,
});
for (options.middlewares) |setup_middleware| { var world = try switch (options.execution) {
try setup_middleware(&world, events); .single_threaded => flow.World.init(0),
}
try setup(&world, events); .thread_share => |thread_share| init: {
try world.run_event(events.load); const cpu_count = @as(u32, @intCast(std.math.clamp(std.Thread.getCpuCount() catch |cpu_count_error| {
@panic(switch (cpu_count_error) {
error.PermissionDenied => "permission denied retrieving CPU count",
error.SystemResources => "system resources are preventing retrieval of the CPU count",
error.Unexpected => "unexpected failure retrieving CPU count",
});
}, 0, std.math.maxInt(u32))));
const ticks_initial = std.time.milliTimestamp(); break: init flow.World.init(coral.scalars.fractional(cpu_count, thread_share) orelse 0);
var ticks_previous = ticks_initial; },
var accumulated_time = @as(f64, 0); };
while (app.is_running) { defer world.deinit();
const ticks_current = std.time.milliTimestamp();
const milliseconds_per_second = 1000.0;
const delta_time = @as(f64, @floatFromInt(ticks_current - ticks_previous)) / milliseconds_per_second;
app.elapsed_time = @as(f64, @floatFromInt(ticks_current - ticks_initial)) / milliseconds_per_second; const events = App.Events{
ticks_previous = ticks_current; .load = try world.create_event("load"),
accumulated_time += delta_time; .pre_update = try world.create_event("pre-update"),
.update = try world.create_event("update"),
.post_update = try world.create_event("post-update"),
.render = try world.create_event("render"),
.finish = try world.create_event("finish"),
.exit = try world.create_event("exit"),
};
try world.run_event(events.pre_update); const app = try world.set_get_state(App{
.events = &events,
.target_frame_time = 1.0 / @as(f64, @floatFromInt(options.tick_rate)),
.elapsed_time = 0,
.is_running = true,
});
while (accumulated_time >= app.target_frame_time) : (accumulated_time -= app.target_frame_time) { for (options.middlewares) |setup_middleware| {
try world.run_event(events.update); try setup_middleware(&world, events);
}
try setup(&world, events);
try world.run_event(events.load);
const ticks_initial = std.time.milliTimestamp();
var ticks_previous = ticks_initial;
var accumulated_time = @as(f64, 0);
while (app.is_running) {
const ticks_current = std.time.milliTimestamp();
const milliseconds_per_second = 1000.0;
const delta_time = @as(f64, @floatFromInt(ticks_current - ticks_previous)) / milliseconds_per_second;
app.elapsed_time = @as(f64, @floatFromInt(ticks_current - ticks_initial)) / milliseconds_per_second;
ticks_previous = ticks_current;
accumulated_time += delta_time;
try world.run_event(events.pre_update);
while (accumulated_time >= app.target_frame_time) : (accumulated_time -= app.target_frame_time) {
try world.run_event(events.update);
}
try world.run_event(events.post_update);
try world.run_event(events.render);
try world.run_event(events.finish);
}
try world.run_event(events.exit);
} }
};
try world.run_event(events.post_update); return Start.main;
try world.run_event(events.render);
try world.run_event(events.finish);
}
try world.run_event(events.exit);
} }
pub const system_fn = flow.system_fn; pub const system_fn = flow.system_fn;