Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only allow main loop to be controlled by platform, and remove some build options #1331

Merged
merged 4 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});

const sysgpu_backend = b.option(SysgpuBackend, "sysgpu_backend", "sysgpu API backend") orelse .default;
const core_platform = b.option(Platform, "core_platform", "mach core platform to use") orelse Platform.fromTarget(target.result);

const build_examples = b.option(bool, "examples", "build/install examples specifically");
const build_libs = b.option(bool, "libs", "build/install libraries specifically");
Expand All @@ -68,7 +67,6 @@ pub fn build(b: *std.Build) !void {
build_options.addOption(bool, "want_sysaudio", want_sysaudio);
build_options.addOption(bool, "want_sysgpu", want_sysgpu);
build_options.addOption(SysgpuBackend, "sysgpu_backend", sysgpu_backend);
build_options.addOption(Platform, "core_platform", core_platform);

var examples = [_]Example{
.{ .name = "core-custom-entrypoint", .deps = &.{} },
Expand Down
23 changes: 2 additions & 21 deletions examples/core-custom-entrypoint/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,6 @@ pub fn main() !void {
var mods: Modules = undefined;
try mods.init(allocator);

// On some platforms, you can drive the mach.Core main loop yourself - but this isn't possible
// on all platforms. If mach.Core.non_blocking is set to true, and the platform supports
// non-blocking mode, then .mach_core.main will return without blocking. Otherwise it will block
// forever and app.run(.main) will never return.
if (mach.Core.supports_non_blocking) {
defer mods.deinit(allocator);

mach.Core.non_blocking = true;

const app = mods.get(.app);
app.run(.main);

// If you are driving the main loop yourself, you should call tick until exit.
const core = mods.get(.mach_core);
while (mods.mods.mach_core.state != .exited) {
core.run(.tick);
}
} else {
const app = mods.get(.app);
app.run(.main);
}
const app = mods.get(.app);
app.run(.main);
}
68 changes: 15 additions & 53 deletions src/Core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,8 @@ const log = std.log.scoped(.mach);

const Core = @This();

// Whether or not you can drive the main loop in a non-blocking fashion, or if the underlying
// platform must take control and drive the main loop itself.
pub const supports_non_blocking = switch (build_options.core_platform) {
// Platforms that support non-blocking mode.
.linux => true,
.windows => true,
.null => true,

// Platforms which take control of the main loop.
.wasm => false,
.darwin => false,
};

const EventQueue = std.fifo.LinearFifo(Event, .Dynamic);

/// Set this to true if you intend to drive the main loop yourself.
///
/// A panic will occur if `supports_non_blocking == false` for the platform.
pub var non_blocking = false;

pub const mach_module = .mach_core;

pub const mach_systems = .{ .main, .init, .tick, .presentFrame, .deinit };
Expand Down Expand Up @@ -277,37 +259,12 @@ pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
core_mod.run(core.on_tick.?);
core_mod.call(.presentFrame);

// If the user doesn't want mach.Core to take control of the main loop, we bail out - the next
// app tick is already scheduled to run in the future and they'll .present_frame to return
// control to us later.
if (non_blocking) {
if (!supports_non_blocking) std.debug.panic(
"mach.Core: platform {s} does not support non_blocking=true mode.",
.{@tagName(build_options.core_platform)},
);
return;
}
// Platform drives the main loop.
Platform.run(platform_update_callback, .{ core, core_mod });

// The user wants mach.Core to take control of the main loop.
if (supports_non_blocking) {
while (core.state != .exited) {
try Platform.tick(core);
core_mod.run(core.on_tick.?);
core_mod.call(.presentFrame);
}

// Don't return, because Platform.run wouldn't either (marked noreturn due to underlying
// platform APIs never returning.)
std.process.exit(0);
} else {
// Platform drives the main loop.
Platform.run(platform_update_callback, .{ core, core_mod });

// Platform.run should be marked noreturn, so this shouldn't ever run. But just in case we
// accidentally introduce a different Platform.run in the future, we put an exit here for
// good measure.
std.process.exit(0);
}
// Platform.run is marked noreturn on some platforms, but not all, so this is here for the
// platforms that do return
std.process.exit(0);
}

fn platform_update_callback(core: *Core, core_mod: mach.Mod(Core)) !bool {
Expand Down Expand Up @@ -463,12 +420,17 @@ pub fn detectBackendType(allocator: std.mem.Allocator) !gpu.BackendType {
@panic("unknown MACH_GPU_BACKEND type");
}

const Platform = switch (build_options.core_platform) {
.wasm => @panic("TODO: support mach.Core WASM platform"),
const Platform = switch (builtin.target.os.tag) {
.wasi => @panic("TODO: support mach.Core WASM platform"),
.ios => @panic("TODO: support mach.Core IOS platform"),
.windows => @import("core/Windows.zig"),
.linux => @import("core/Linux.zig"),
.darwin => @import("core/Darwin.zig"),
.null => @import("core/Null.zig"),
.linux => blk: {
if (builtin.target.abi.isAndroid())
@panic("TODO: support mach.Core Android platform");
break :blk @import("core/Linux.zig");
},
.macos => @import("core/Darwin.zig"),
else => {},
};

pub const InputState = struct {
Expand Down
32 changes: 9 additions & 23 deletions src/core/Linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,20 @@ backend: Backend,
const MISSING_FEATURES_X11 = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/cursor" };
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/cursor" };

pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) void {
while (@call(.auto, on_each_update_fn, args_tuple) catch false) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch false here is sus, need to investigate better error handling for init of platforms

}

pub fn tick(core: *Core) !void {
var windows = core.windows.slice();
while (windows.next()) |window_id| {
const native_opt: ?Native = core.windows.get(window_id, .native);
if (native_opt) |native| {
check_for_mach_updates(core, window_id);
// checks for updates in mach object fields
const core_window = core.windows.getValue(window_id);
if (core.windows.updated(window_id, .title)) {
setTitle(&native, core_window.title);
}
// check for display server events
switch (native) {
.x11 => try X11.tick(window_id),
Expand Down Expand Up @@ -129,17 +137,6 @@ pub fn initWindow(
try warnAboutIncompleteFeatures(desired_backend, &MISSING_FEATURES_X11, &MISSING_FEATURES_WAYLAND, core.allocator);
}

// pub fn deinit(linux: *Linux) void {
// if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();
//
// linux.allocator.free(linux.title);
//
// switch (linux.backend) {
// .wayland => linux.backend.wayland.deinit(linux),
// .x11 => linux.backend.x11.deinit(linux),
// }
// }

pub fn update(linux: *Linux) !void {
switch (linux.backend) {
.wayland => try linux.backend.wayland.update(linux),
Expand Down Expand Up @@ -187,17 +184,6 @@ pub fn setCursorShape(_: *Linux, _: CursorShape) void {
return;
}

/// Checks for updates in mach object fields. Does nothing if window is not initialized.
fn check_for_mach_updates(core: *Core, window_id: mach.ObjectID) void {
const core_window = core.windows.getValue(window_id);
const native = &core_window.native;
if (native.*) |n| {
if (core.windows.updated(window_id, .title)) {
setTitle(&n, core_window.title);
}
}
}

/// Check if gamemode should be activated
pub fn wantGamemode(allocator: std.mem.Allocator) error{ OutOfMemory, InvalidWtf8 }!bool {
const use_gamemode = std.process.getEnvVarOwned(
Expand Down
89 changes: 0 additions & 89 deletions src/core/Null.zig

This file was deleted.

4 changes: 4 additions & 0 deletions src/core/Windows.zig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ pub const Context = struct {
window_id: mach.ObjectID,
};

pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) void {
while (@call(.auto, on_each_update_fn, args_tuple) catch false) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

}

pub fn tick(core: *Core) !void {
var windows = core.windows.slice();
while (windows.next()) |window_id| {
Expand Down
7 changes: 0 additions & 7 deletions src/core/linux/Wayland.zig
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,6 @@ pub fn initWindow(
try core.initWindow(window_id);
}

// pub fn deinit(
// wl: *Wayland,
// linux: *Linux,
// ) void {
// linux.allocator.destroy(wl.surface_descriptor);
// }

pub fn tick(window_id: mach.ObjectID) !void {
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;

Expand Down
30 changes: 0 additions & 30 deletions src/core/linux/X11.zig
Original file line number Diff line number Diff line change
Expand Up @@ -217,36 +217,6 @@ pub fn initWindow(
try core.initWindow(window_id);
}

// pub fn deinit(
// x11: *X11,
// linux: *Linux,
// ) void {
// linux.allocator.destroy(x11.surface_descriptor);
// for (x11.cursors) |cur| {
// if (cur) |_| {
// // _ = x11.libx11.XFreeCursor(x11.display, cur.?);
// }
// }
// if (x11.libxcursor) |*libxcursor| {
// libxcursor.handle.close();
// }
// if (x11.libxrr) |*libxrr| {
// libxrr.handle.close();
// }
// if (x11.libgl) |*libgl| {
// if (x11.gl_ctx) |gl_ctx| {
// libgl.glXDestroyContext(x11.display, gl_ctx);
// }
// libgl.handle.close();
// }
// _ = x11.libx11.XUnmapWindow(x11.display, x11.window);
// _ = x11.libx11.XDestroyWindow(x11.display, x11.window);
// _ = x11.libx11.XCloseDisplay(x11.display);
// x11.libx11.handle.close();
// std.posix.close(x11.empty_event_pipe[0]);
// std.posix.close(x11.empty_event_pipe[1]);
// }

// Called on the main thread
pub fn tick(window_id: mach.ObjectID) !void {
var core_window = core_ptr.windows.getValue(window_id);
Expand Down
Loading