From 3bb45c75a1032fdd7bdfde781f7ccedea0dac4e9 Mon Sep 17 00:00:00 2001 From: iddev5 Date: Tue, 17 May 2022 13:20:19 +0530 Subject: [PATCH] mach: introduce cross platform Timer abstraction This Timer uses std.time.Timer as backing timer in native platforms, and will use custom timers for special platforms (wasm, android?, ios?). Unlike std.time.Timer, its primary API is focused on floats. Also meant to provides some convenient functions alongside base ones. Follows std.time.Timer API, but methods by default return f32 i.e non-precise variant with precise variants available returning u64. --- examples/fractal-cube/main.zig | 6 ++--- examples/instanced-cube/main.zig | 6 ++--- examples/rotating-cube/main.zig | 6 ++--- examples/textured-cube/main.zig | 6 ++--- examples/two-cubes/main.zig | 6 ++--- src/Engine.zig | 7 +++--- src/Timer.zig | 41 ++++++++++++++++++++++++++++++++ src/main.zig | 1 + src/native.zig | 4 ++-- 9 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 src/Timer.zig diff --git a/examples/fractal-cube/main.zig b/examples/fractal-cube/main.zig index 05ef551f..15af6ff5 100755 --- a/examples/fractal-cube/main.zig +++ b/examples/fractal-cube/main.zig @@ -22,7 +22,7 @@ const UniformBufferObject = struct { mat: zm.Mat, }; -var timer: std.time.Timer = undefined; +var timer: mach.Timer = undefined; pipeline: gpu.RenderPipeline, queue: gpu.Queue, @@ -38,7 +38,7 @@ sampler: gpu.Sampler, bgl: gpu.BindGroupLayout, pub fn init(app: *App, engine: *mach.Engine) !void { - timer = try std.time.Timer.start(); + timer = try mach.Timer.start(); engine.core.setKeyCallback(struct { fn callback(_: *App, eng: *mach.Engine, key: mach.Key, action: mach.Action) void { @@ -269,7 +269,7 @@ pub fn update(app: *App, engine: *mach.Engine) !bool { }; { - const time = @intToFloat(f32, timer.read()) / @as(f32, std.time.ns_per_s); + const time = timer.read(); const model = zm.mul(zm.rotationX(time * (std.math.pi / 2.0)), zm.rotationZ(time * (std.math.pi / 2.0))); const view = zm.lookAtRh( zm.f32x4(0, -4, 0, 1), diff --git a/examples/instanced-cube/main.zig b/examples/instanced-cube/main.zig index 47aac605..b562a18d 100755 --- a/examples/instanced-cube/main.zig +++ b/examples/instanced-cube/main.zig @@ -10,7 +10,7 @@ const UniformBufferObject = struct { mat: zm.Mat, }; -var timer: std.time.Timer = undefined; +var timer: mach.Timer = undefined; pipeline: gpu.RenderPipeline, queue: gpu.Queue, @@ -21,7 +21,7 @@ bind_group: gpu.BindGroup, const App = @This(); pub fn init(app: *App, engine: *mach.Engine) !void { - timer = try std.time.Timer.start(); + timer = try mach.Timer.start(); engine.core.setKeyCallback(struct { fn callback(_: *App, eng: *mach.Engine, key: mach.Key, action: mach.Action) void { @@ -171,7 +171,7 @@ pub fn update(app: *App, engine: *mach.Engine) !bool { ); var ubos: [16]UniformBufferObject = undefined; - const time = @intToFloat(f32, timer.read()) / @as(f32, std.time.ns_per_s); + const time = timer.read(); const step: f32 = 4.0; var m: u8 = 0; var x: u8 = 0; diff --git a/examples/rotating-cube/main.zig b/examples/rotating-cube/main.zig index 82abb27a..520edf1c 100755 --- a/examples/rotating-cube/main.zig +++ b/examples/rotating-cube/main.zig @@ -12,7 +12,7 @@ const UniformBufferObject = struct { mat: zm.Mat, }; -var timer: std.time.Timer = undefined; +var timer: mach.Timer = undefined; pipeline: gpu.RenderPipeline, queue: gpu.Queue, @@ -21,7 +21,7 @@ uniform_buffer: gpu.Buffer, bind_group: gpu.BindGroup, pub fn init(app: *App, engine: *mach.Engine) !void { - timer = try std.time.Timer.start(); + timer = try mach.Timer.start(); // TODO: higher level input handlers engine.core.setKeyCallback(struct { @@ -173,7 +173,7 @@ pub fn update(app: *App, engine: *mach.Engine) !bool { }; { - const time = @intToFloat(f32, timer.read()) / @as(f32, std.time.ns_per_s); + const time = timer.read(); const model = zm.mul(zm.rotationX(time * (std.math.pi / 2.0)), zm.rotationZ(time * (std.math.pi / 2.0))); const view = zm.lookAtRh( zm.f32x4(0, 4, 2, 1), diff --git a/examples/textured-cube/main.zig b/examples/textured-cube/main.zig index d280e6db..2205c970 100644 --- a/examples/textured-cube/main.zig +++ b/examples/textured-cube/main.zig @@ -11,7 +11,7 @@ const UniformBufferObject = struct { mat: zm.Mat, }; -var timer: std.time.Timer = undefined; +var timer: mach.Timer = undefined; pipeline: gpu.RenderPipeline, queue: gpu.Queue, @@ -24,7 +24,7 @@ depth_size: mach.Size, const App = @This(); pub fn init(app: *App, engine: *mach.Engine) !void { - timer = try std.time.Timer.start(); + timer = try mach.Timer.start(); engine.core.setKeyCallback(struct { fn callback(_: *App, eng: *mach.Engine, key: mach.Key, action: mach.Action) void { @@ -239,7 +239,7 @@ pub fn update(app: *App, engine: *mach.Engine) !bool { }; { - const time = @intToFloat(f32, timer.read()) / @as(f32, std.time.ns_per_s); + const time = timer.read(); const model = zm.mul(zm.rotationX(time * (std.math.pi / 2.0)), zm.rotationZ(time * (std.math.pi / 2.0))); const view = zm.lookAtRh( zm.f32x4(0, 4, 2, 1), diff --git a/examples/two-cubes/main.zig b/examples/two-cubes/main.zig index a4b9307f..c4d82ac2 100755 --- a/examples/two-cubes/main.zig +++ b/examples/two-cubes/main.zig @@ -10,7 +10,7 @@ const UniformBufferObject = struct { mat: zm.Mat, }; -var timer: std.time.Timer = undefined; +var timer: mach.Timer = undefined; pipeline: gpu.RenderPipeline, queue: gpu.Queue, @@ -22,7 +22,7 @@ bind_group2: gpu.BindGroup, const App = @This(); pub fn init(app: *App, engine: *mach.Engine) !void { - timer = try std.time.Timer.start(); + timer = try mach.Timer.start(); engine.core.setKeyCallback(struct { fn callback(_: *App, eng: *mach.Engine, key: mach.Key, action: mach.Action) void { @@ -189,7 +189,7 @@ pub fn update(app: *App, engine: *mach.Engine) !bool { }; { - const time = @intToFloat(f32, timer.read()) / @as(f32, std.time.ns_per_s); + const time = timer.read(); const rotation1 = zm.mul(zm.rotationX(time * (std.math.pi / 2.0)), zm.rotationZ(time * (std.math.pi / 2.0))); const rotation2 = zm.mul(zm.rotationZ(time * (std.math.pi / 2.0)), zm.rotationX(time * (std.math.pi / 2.0))); const model1 = zm.mul(rotation1, zm.translation(-2, 0, 0)); diff --git a/src/Engine.zig b/src/Engine.zig index 08744d08..85ad47dc 100644 --- a/src/Engine.zig +++ b/src/Engine.zig @@ -5,6 +5,7 @@ const gpu = @import("gpu"); const App = @import("app"); const structs = @import("structs.zig"); const enums = @import("enums.zig"); +const Timer = @import("Timer.zig"); const Engine = @This(); @@ -23,9 +24,9 @@ options: structs.Options, /// For example, if you are animating a cube which should rotate 360 degrees every second, /// instead of writing (360.0 / 60.0) and assuming the frame rate is 60hz, write /// (360.0 * engine.delta_time) -delta_time: f64 = 0, +delta_time: f32 = 0, delta_time_ns: u64 = 0, -timer: std.time.Timer, +timer: Timer, pub const Core = struct { internal: GetCoreInternalType(), @@ -64,7 +65,7 @@ pub fn init(allocator: std.mem.Allocator, options: structs.Options) !Engine { var engine = Engine{ .allocator = allocator, .options = options, - .timer = try std.time.Timer.start(), + .timer = try Timer.start(), .core = undefined, .gpu_driver = undefined, }; diff --git a/src/Timer.zig b/src/Timer.zig new file mode 100644 index 00000000..c02fc6d9 --- /dev/null +++ b/src/Timer.zig @@ -0,0 +1,41 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +const Timer = @This(); + +backing_timer: BackingTimerType = undefined, + +// TODO: verify declarations and its signatures +const BackingTimerType = if (builtin.cpu.arch == .wasm32) void else std.time.Timer; + +/// Initialize the timer. +pub fn start() !Timer { + return Timer{ + .backing_timer = try BackingTimerType.start(), + }; +} + +/// Reads the timer value since start or the last reset in nanoseconds. +pub fn readPrecise(timer: *Timer) u64 { + return timer.backing_timer.read(); +} + +/// Reads the timer value since start or the last reset in seconds. +pub fn read(timer: *Timer) f32 { + return @intToFloat(f32, timer.readPrecise()) / @intToFloat(f32, std.time.ns_per_s); +} + +/// Resets the timer value to 0/now. +pub fn reset(timer: *Timer) void { + timer.backing_timer.reset(); +} + +/// Returns the current value of the timer in nanoseconds, then resets it. +pub fn lapPrecise(timer: *Timer) u64 { + return timer.backing_timer.lap(); +} + +/// Returns the current value of the timer in seconds, then resets it. +pub fn lap(timer: *Timer) f32 { + return @intToFloat(f32, timer.lapPrecise()) / @intToFloat(f32, std.time.ns_per_s); +} diff --git a/src/main.zig b/src/main.zig index 9afeded3..cd3f80d6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,3 +1,4 @@ pub usingnamespace @import("structs.zig"); pub usingnamespace @import("enums.zig"); pub const Engine = @import("Engine.zig"); +pub const Timer = @import("Timer.zig"); diff --git a/src/native.zig b/src/native.zig index 8379f2ef..c762ab50 100644 --- a/src/native.zig +++ b/src/native.zig @@ -387,8 +387,8 @@ pub fn main() !void { while (!window.shouldClose()) { try glfw.pollEvents(); - engine.delta_time_ns = engine.timer.lap(); - engine.delta_time = @intToFloat(f64, engine.delta_time_ns) / @intToFloat(f64, std.time.ns_per_s); + engine.delta_time_ns = engine.timer.lapPrecise(); + engine.delta_time = @intToFloat(f32, engine.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s); var framebuffer_size = try window.getFramebufferSize(); engine.gpu_driver.target_desc.width = framebuffer_size.width;