core: darwin: More input callbacks, correct framebuffer/window sizes, core has responsibility of swapchain
This commit is contained in:
parent
a10cbc3419
commit
98c303aefc
2 changed files with 178 additions and 209 deletions
239
src/Core.zig
239
src/Core.zig
|
|
@ -209,8 +209,8 @@ pub fn initWindow(core: *Core, window_id: mach.ObjectID) !void {
|
|||
.label = "main swap chain",
|
||||
.usage = core_window.swap_chain_usage,
|
||||
.format = .bgra8_unorm,
|
||||
.width = core_window.width,
|
||||
.height = core_window.height,
|
||||
.width = core_window.framebuffer_width,
|
||||
.height = core_window.framebuffer_height,
|
||||
.present_mode = switch (core_window.vsync_mode) {
|
||||
.none => .immediate,
|
||||
.double => .fifo,
|
||||
|
|
@ -218,10 +218,6 @@ pub fn initWindow(core: *Core, window_id: mach.ObjectID) !void {
|
|||
},
|
||||
};
|
||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||
core_window.framebuffer_format = core_window.swap_chain_descriptor.format;
|
||||
core_window.framebuffer_width = core_window.swap_chain_descriptor.width;
|
||||
core_window.framebuffer_height = core_window.swap_chain_descriptor.height;
|
||||
|
||||
core.pushEvent(.{ .window_open = .{ .window_id = window_id } });
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +232,32 @@ pub fn tick(core: *Core, core_mod: mach.Mod(Core)) !void {
|
|||
core_mod.call(.presentFrame);
|
||||
}
|
||||
|
||||
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
var windows = core.windows.slice();
|
||||
while (windows.next()) |window_id| {
|
||||
var core_window = core.windows.getValue(window_id);
|
||||
defer core.windows.setValueRaw(window_id, core_window);
|
||||
|
||||
mach.sysgpu.Impl.deviceTick(core_window.device);
|
||||
|
||||
core_window.swap_chain.present();
|
||||
}
|
||||
|
||||
// Record to frame rate frequency monitor that a frame was finished.
|
||||
core.frame.tick();
|
||||
|
||||
switch (core.state) {
|
||||
.running => {},
|
||||
.exiting => {
|
||||
core.state = .deinitializing;
|
||||
core_mod.run(core.on_exit.?);
|
||||
core_mod.call(.deinit);
|
||||
},
|
||||
.deinitializing => {},
|
||||
.exited => @panic("application not running"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
if (core.on_tick == null) @panic("core.on_tick callback must be set");
|
||||
if (core.on_exit == null) @panic("core.on_exit callback must be set");
|
||||
|
|
@ -286,11 +308,14 @@ fn platform_update_callback(core: *Core, core_mod: mach.Mod(Core)) !bool {
|
|||
|
||||
core_mod.run(core.on_tick.?);
|
||||
core_mod.call(.presentFrame);
|
||||
//core_mod.call(.processWindowUpdates);
|
||||
|
||||
return core.state != .exited;
|
||||
}
|
||||
|
||||
pub fn exit(core: *Core) void {
|
||||
core.state = .exiting;
|
||||
}
|
||||
|
||||
pub fn deinit(core: *Core) !void {
|
||||
core.state = .exited;
|
||||
|
||||
|
|
@ -369,206 +394,6 @@ pub fn mousePosition(core: *@This()) Position {
|
|||
return core.input_state.mouse_position;
|
||||
}
|
||||
|
||||
// TODO(object)
|
||||
// /// Set refresh rate synchronization mode. Default `.triple`
|
||||
// ///
|
||||
// /// Calling this function also implicitly calls setFrameRateLimit for you:
|
||||
// /// ```
|
||||
// /// .none => setFrameRateLimit(0) // unlimited
|
||||
// /// .double => setFrameRateLimit(0) // unlimited
|
||||
// /// .triple => setFrameRateLimit(2 * max_monitor_refresh_rate)
|
||||
// /// ```
|
||||
// pub inline fn setVSync(core: *@This(), mode: VSyncMode) void {
|
||||
// return core.platform.setVSync(mode);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns refresh rate synchronization mode.
|
||||
// pub inline fn vsync(core: *@This()) VSyncMode {
|
||||
// return core.platform.vsync_mode;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Sets the frame rate limit. Default 0 (unlimited)
|
||||
// ///
|
||||
// /// This is applied *in addition* to the vsync mode.
|
||||
// pub inline fn setFrameRateLimit(core: *@This(), limit: u32) void {
|
||||
// core.frame.target = limit;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the frame rate limit, or zero if unlimited.
|
||||
// pub inline fn frameRateLimit(core: *@This()) u32 {
|
||||
// return core.frame.target;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Set the window size, in subpixel units.
|
||||
// pub inline fn setSize(core: *@This(), value: Size) void {
|
||||
// return core.platform.setSize(value);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the window size, in subpixel units.
|
||||
// pub inline fn size(core: *@This()) Size {
|
||||
// return core.platform.size;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn setCursorMode(core: *@This(), mode: CursorMode) void {
|
||||
// return core.platform.setCursorMode(mode);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn cursorMode(core: *@This()) CursorMode {
|
||||
// return core.platform.cursorMode();
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn setCursorShape(core: *@This(), cursor: CursorShape) void {
|
||||
// return core.platform.setCursorShape(cursor);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn cursorShape(core: *@This()) CursorShape {
|
||||
// return core.platform.cursorShape();
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Sets the minimum target frequency of the input handling thread.
|
||||
// ///
|
||||
// /// Input handling (the main thread) runs at a variable frequency. The thread blocks until there are
|
||||
// /// input events available, or until it needs to unblock in order to achieve the minimum target
|
||||
// /// frequency which is your collaboration point of opportunity with the main thread.
|
||||
// ///
|
||||
// /// For example, by default (`setInputFrequency(1)`) mach-core will aim to invoke `updateMainThread`
|
||||
// /// at least once per second (but potentially much more, e.g. once per every mouse movement or
|
||||
// /// keyboard button press.) If you were to increase the input frequency to say 60hz e.g.
|
||||
// /// `setInputFrequency(60)` then mach-core will aim to invoke your `updateMainThread` 60 times per
|
||||
// /// second.
|
||||
// ///
|
||||
// /// An input frequency of zero implies unlimited, in which case the main thread will busy-wait.
|
||||
// ///
|
||||
// /// # Multithreaded mach-core behavior
|
||||
// ///
|
||||
// /// On some platforms, mach-core is able to handle input and rendering independently for
|
||||
// /// improved performance and responsiveness.
|
||||
// ///
|
||||
// /// | Platform | Threading |
|
||||
// /// |----------|-----------------|
|
||||
// /// | Desktop | Multi threaded |
|
||||
// /// | Browser | Single threaded |
|
||||
// /// | Mobile | TBD |
|
||||
// ///
|
||||
// /// On single-threaded platforms, `update` and the (optional) `updateMainThread` callback are
|
||||
// /// invoked in sequence, one after the other, on the same thread.
|
||||
// ///
|
||||
// /// On multi-threaded platforms, `init` and `deinit` are called on the main thread, while `update`
|
||||
// /// is called on a separate rendering thread. The (optional) `updateMainThread` callback can be
|
||||
// /// used in cases where you must run a function on the main OS thread (such as to open a native
|
||||
// /// file dialog on macOS, since many system GUI APIs must be run on the main OS thread.) It is
|
||||
// /// advised you do not use this callback to run any code except when absolutely neccessary, as
|
||||
// /// it is in direct contention with input handling.
|
||||
// ///
|
||||
// /// APIs which are not accessible from a specific thread are declared as such, otherwise can be
|
||||
// /// called from any thread as they are internally synchronized.
|
||||
// pub inline fn setInputFrequency(core: *@This(), input_frequency: u32) void {
|
||||
// core.input.target = input_frequency;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the input frequency, or zero if unlimited (busy-waiting mode)
|
||||
// pub inline fn inputFrequency(core: *@This()) u32 {
|
||||
// return core.input.target;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the actual number of frames rendered (`update` calls that returned) in the last second.
|
||||
// ///
|
||||
// /// This is updated once per second.
|
||||
// pub inline fn frameRate(core: *@This()) u32 {
|
||||
// return core.frame.rate;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the actual number of input thread iterations in the last second. See setInputFrequency
|
||||
// /// for what this means.
|
||||
// ///
|
||||
// /// This is updated once per second.
|
||||
// pub inline fn inputRate(core: *@This()) u32 {
|
||||
// return core.input.rate;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the underlying native NSWindow pointer
|
||||
// ///
|
||||
// /// May only be called on macOS.
|
||||
// pub fn nativeWindowCocoa(core: *@This()) *anyopaque {
|
||||
// return core.platform.nativeWindowCocoa();
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the underlying native Windows' HWND pointer
|
||||
// ///
|
||||
// /// May only be called on Windows.
|
||||
// pub fn nativeWindowWin32(core: *@This()) std.os.windows.HWND {
|
||||
// return core.platform.nativeWindowWin32();
|
||||
// }
|
||||
|
||||
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
var windows = core.windows.slice();
|
||||
while (windows.next()) |window_id| {
|
||||
var core_window = core.windows.getValue(window_id);
|
||||
defer core.windows.setValueRaw(window_id, core_window);
|
||||
|
||||
mach.sysgpu.Impl.deviceTick(core_window.device);
|
||||
|
||||
core_window.swap_chain.present();
|
||||
|
||||
// Update swapchain for the next frame
|
||||
if (core_window.swap_chain_update.isSet()) blk: {
|
||||
core_window.swap_chain_update.reset();
|
||||
|
||||
switch (core_window.vsync_mode) {
|
||||
.triple => core.frame.target = 2 * core_window.refresh_rate,
|
||||
else => core.frame.target = 0,
|
||||
}
|
||||
|
||||
if (core_window.width == 0 or core_window.height == 0) break :blk;
|
||||
|
||||
core_window.swap_chain_descriptor.present_mode = switch (core_window.vsync_mode) {
|
||||
.none => .immediate,
|
||||
.double => .fifo,
|
||||
.triple => .mailbox,
|
||||
};
|
||||
|
||||
core_window.swap_chain_descriptor.width = core_window.width;
|
||||
core_window.swap_chain_descriptor.height = core_window.height;
|
||||
core_window.swap_chain.release();
|
||||
|
||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
// Record to frame rate frequency monitor that a frame was finished.
|
||||
core.frame.tick();
|
||||
|
||||
switch (core.state) {
|
||||
.running => {},
|
||||
.exiting => {
|
||||
core.state = .deinitializing;
|
||||
core_mod.run(core.on_exit.?);
|
||||
core_mod.call(.deinit);
|
||||
},
|
||||
.deinitializing => {},
|
||||
.exited => @panic("application not running"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(core: *Core) void {
|
||||
core.state = .exiting;
|
||||
}
|
||||
|
||||
inline fn requestAdapterCallback(
|
||||
context: *RequestAdapterResponse,
|
||||
status: gpu.RequestAdapterStatus,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue