mach: merge and remove the extra layer of indirection caused by Core and
GpuDriver Core and GpuDriver both are merged into one type called Platform. Also previously the fields and methods which were called as ``engine.core.field`` will now be ``engine.field`` i.e an extra layer is removed.
This commit is contained in:
parent
3961073084
commit
50fe649ab1
4 changed files with 225 additions and 263 deletions
|
|
@ -10,12 +10,6 @@ const Timer = @import("Timer.zig");
|
||||||
|
|
||||||
const Engine = @This();
|
const Engine = @This();
|
||||||
|
|
||||||
/// Window, events, inputs etc.
|
|
||||||
core: Core,
|
|
||||||
|
|
||||||
/// WebGPU driver - stores device, swap chains, targets and more
|
|
||||||
gpu_driver: GpuDriver,
|
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
|
||||||
options: structs.Options,
|
options: structs.Options,
|
||||||
|
|
@ -29,62 +23,50 @@ delta_time: f32 = 0,
|
||||||
delta_time_ns: u64 = 0,
|
delta_time_ns: u64 = 0,
|
||||||
timer: Timer,
|
timer: Timer,
|
||||||
|
|
||||||
pub const Core = struct {
|
device: gpu.Device,
|
||||||
internal: platform.CoreType,
|
backend_type: gpu.Adapter.BackendType,
|
||||||
|
swap_chain: ?gpu.SwapChain,
|
||||||
|
swap_chain_format: gpu.Texture.Format,
|
||||||
|
|
||||||
pub fn setShouldClose(core: *Core, value: bool) void {
|
surface: ?gpu.Surface,
|
||||||
core.internal.setShouldClose(value);
|
current_desc: gpu.SwapChain.Descriptor,
|
||||||
}
|
target_desc: gpu.SwapChain.Descriptor,
|
||||||
|
|
||||||
// Returns the framebuffer size, in subpixel units.
|
internal: platform.Type,
|
||||||
//
|
|
||||||
// e.g. returns 1280x960 on macOS for a window that is 640x480
|
|
||||||
pub fn getFramebufferSize(core: *Core) structs.Size {
|
|
||||||
return core.internal.getFramebufferSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the widow size, in pixel units.
|
|
||||||
//
|
|
||||||
// e.g. returns 640x480 on macOS for a window that is 640x480
|
|
||||||
pub fn getWindowSize(core: *Core) structs.Size {
|
|
||||||
return core.internal.getWindowSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setSizeLimits(core: *Core, min: structs.SizeOptional, max: structs.SizeOptional) !void {
|
|
||||||
return core.internal.setSizeLimits(min, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pollEvent(core: *Core) ?structs.Event {
|
|
||||||
return core.internal.pollEvent();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const GpuDriver = struct {
|
|
||||||
internal: platform.GpuDriverType,
|
|
||||||
|
|
||||||
device: gpu.Device,
|
|
||||||
backend_type: gpu.Adapter.BackendType,
|
|
||||||
swap_chain: ?gpu.SwapChain,
|
|
||||||
swap_chain_format: gpu.Texture.Format,
|
|
||||||
|
|
||||||
surface: ?gpu.Surface,
|
|
||||||
current_desc: gpu.SwapChain.Descriptor,
|
|
||||||
target_desc: gpu.SwapChain.Descriptor,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, options: structs.Options) !Engine {
|
pub fn init(allocator: std.mem.Allocator, options: structs.Options) !Engine {
|
||||||
var engine = Engine{
|
var engine: Engine = undefined;
|
||||||
.allocator = allocator,
|
engine.allocator = allocator;
|
||||||
.options = options,
|
engine.options = options;
|
||||||
.timer = try Timer.start(),
|
engine.timer = try Timer.start();
|
||||||
.core = undefined,
|
|
||||||
.gpu_driver = undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Note: if in future, there is a conflict in init() signature of different backends,
|
engine.internal = try platform.Type.init(allocator, &engine);
|
||||||
// move these calls to the entry point file, which is native.zig for Glfw, for example
|
|
||||||
engine.core.internal = try platform.CoreType.init(allocator, &engine);
|
|
||||||
engine.gpu_driver.internal = try platform.GpuDriverType.init(allocator, &engine);
|
|
||||||
|
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setShouldClose(engine: *Engine, value: bool) void {
|
||||||
|
engine.internal.setShouldClose(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the framebuffer size, in subpixel units.
|
||||||
|
//
|
||||||
|
// e.g. returns 1280x960 on macOS for a window that is 640x480
|
||||||
|
pub fn getFramebufferSize(engine: *Engine) structs.Size {
|
||||||
|
return engine.internal.getFramebufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the widow size, in pixel units.
|
||||||
|
//
|
||||||
|
// e.g. returns 1280x960 on macOS for a window that is 640x480
|
||||||
|
pub fn getWindowSize(engine: *Engine) structs.Size {
|
||||||
|
return engine.internal.getWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setSizeLimits(engine: *Engine, min: structs.SizeOptional, max: structs.SizeOptional) !void {
|
||||||
|
return engine.internal.setSizeLimits(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pollEvent(engine: *Engine) ?structs.Event {
|
||||||
|
return engine.internal.pollEvent();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,5 @@ const builtin = @import("builtin");
|
||||||
const Platform = if (builtin.cpu.arch == .wasm32) @import("platform/wasm.zig") else @import("platform/native.zig");
|
const Platform = if (builtin.cpu.arch == .wasm32) @import("platform/wasm.zig") else @import("platform/native.zig");
|
||||||
|
|
||||||
// TODO: verify declarations and its signatures
|
// TODO: verify declarations and its signatures
|
||||||
pub const CoreType = Platform.Core;
|
pub const Type = Platform.Platform;
|
||||||
pub const GpuDriverType = Platform.GpuDriver;
|
|
||||||
pub const BackingTimerType = Platform.BackingTimer;
|
pub const BackingTimerType = Platform.BackingTimer;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const enums = @import("../enums.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
pub const Core = struct {
|
pub const Platform = struct {
|
||||||
window: glfw.Window,
|
window: glfw.Window,
|
||||||
backend_type: gpu.Adapter.BackendType,
|
backend_type: gpu.Adapter.BackendType,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
|
@ -18,18 +18,20 @@ pub const Core = struct {
|
||||||
last_window_size: structs.Size,
|
last_window_size: structs.Size,
|
||||||
last_framebuffer_size: structs.Size,
|
last_framebuffer_size: structs.Size,
|
||||||
|
|
||||||
|
native_instance: gpu.NativeInstance,
|
||||||
|
|
||||||
const EventQueue = std.TailQueue(structs.Event);
|
const EventQueue = std.TailQueue(structs.Event);
|
||||||
const EventNode = EventQueue.Node;
|
const EventNode = EventQueue.Node;
|
||||||
|
|
||||||
const UserPtr = struct {
|
const UserPtr = struct {
|
||||||
core: *Core,
|
platform: *Platform,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Core {
|
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Platform {
|
||||||
const options = engine.options;
|
const options = engine.options;
|
||||||
const backend_type = try util.detectBackendType(allocator);
|
const backend_type = try util.detectBackendType(allocator);
|
||||||
|
|
||||||
glfw.setErrorCallback(Core.errorCallback);
|
glfw.setErrorCallback(Platform.errorCallback);
|
||||||
try glfw.init(.{});
|
try glfw.init(.{});
|
||||||
|
|
||||||
// Create the test window and discover adapters using it (esp. for OpenGL)
|
// Create the test window and discover adapters using it (esp. for OpenGL)
|
||||||
|
|
@ -47,37 +49,160 @@ pub const Core = struct {
|
||||||
const window_size = try window.getSize();
|
const window_size = try window.getSize();
|
||||||
const framebuffer_size = try window.getFramebufferSize();
|
const framebuffer_size = try window.getFramebufferSize();
|
||||||
|
|
||||||
return Core{
|
const backend_procs = c.machDawnNativeGetProcs();
|
||||||
|
c.dawnProcSetProcs(backend_procs);
|
||||||
|
|
||||||
|
const instance = c.machDawnNativeInstance_init();
|
||||||
|
var native_instance = gpu.NativeInstance.wrap(c.machDawnNativeInstance_get(instance).?);
|
||||||
|
|
||||||
|
// Discover e.g. OpenGL adapters.
|
||||||
|
try util.discoverAdapters(instance, window, backend_type);
|
||||||
|
|
||||||
|
// Request an adapter.
|
||||||
|
//
|
||||||
|
// TODO: It would be nice if we could use gpu_interface.waitForAdapter here, however the webgpu.h
|
||||||
|
// API does not yet have a way to specify what type of backend you want (vulkan, opengl, etc.)
|
||||||
|
// In theory, I suppose we shouldn't need to and Dawn should just pick the best adapter - but in
|
||||||
|
// practice if Vulkan is not supported today waitForAdapter/requestAdapter merely generates an error.
|
||||||
|
//
|
||||||
|
// const gpu_interface = native_instance.interface();
|
||||||
|
// const backend_adapter = switch (gpu_interface.waitForAdapter(&.{
|
||||||
|
// .power_preference = .high_performance,
|
||||||
|
// })) {
|
||||||
|
// .adapter => |v| v,
|
||||||
|
// .err => |err| {
|
||||||
|
// std.debug.print("mach: failed to get adapter: error={} {s}\n", .{ err.code, err.message });
|
||||||
|
// std.process.exit(1);
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
const adapters = c.machDawnNativeInstance_getAdapters(instance);
|
||||||
|
var dawn_adapter: ?c.MachDawnNativeAdapter = null;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < c.machDawnNativeAdapters_length(adapters)) : (i += 1) {
|
||||||
|
const adapter = c.machDawnNativeAdapters_index(adapters, i);
|
||||||
|
const properties = c.machDawnNativeAdapter_getProperties(adapter);
|
||||||
|
const found_backend_type = @intToEnum(gpu.Adapter.BackendType, c.machDawnNativeAdapterProperties_getBackendType(properties));
|
||||||
|
if (found_backend_type == backend_type) {
|
||||||
|
dawn_adapter = adapter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dawn_adapter == null) {
|
||||||
|
std.debug.print("mach: no matching adapter found for {s}", .{@tagName(backend_type)});
|
||||||
|
std.debug.print("-> maybe try GPU_BACKEND=opengl ?\n", .{});
|
||||||
|
std.process.exit(1);
|
||||||
|
}
|
||||||
|
std.debug.assert(dawn_adapter != null);
|
||||||
|
const backend_adapter = gpu.NativeInstance.fromWGPUAdapter(c.machDawnNativeAdapter_get(dawn_adapter.?).?);
|
||||||
|
|
||||||
|
// Print which adapter we are going to use.
|
||||||
|
const props = backend_adapter.properties;
|
||||||
|
std.debug.print("mach: found {s} backend on {s} adapter: {s}, {s}\n", .{
|
||||||
|
gpu.Adapter.backendTypeName(props.backend_type),
|
||||||
|
gpu.Adapter.typeName(props.adapter_type),
|
||||||
|
props.name,
|
||||||
|
props.driver_description,
|
||||||
|
});
|
||||||
|
|
||||||
|
const device = switch (backend_adapter.waitForDevice(&.{
|
||||||
|
.required_features = options.required_features,
|
||||||
|
.required_limits = options.required_limits,
|
||||||
|
})) {
|
||||||
|
.device => |v| v,
|
||||||
|
.err => |err| {
|
||||||
|
// TODO: return a proper error type
|
||||||
|
std.debug.print("mach: failed to get device: error={} {s}\n", .{ err.code, err.message });
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// If targeting OpenGL, we can't use the newer WGPUSurface API. Instead, we need to use the
|
||||||
|
// older Dawn-specific API. https://bugs.chromium.org/p/dawn/issues/detail?id=269&q=surface&can=2
|
||||||
|
const use_legacy_api = backend_type == .opengl or backend_type == .opengles;
|
||||||
|
var descriptor: gpu.SwapChain.Descriptor = undefined;
|
||||||
|
var swap_chain: ?gpu.SwapChain = null;
|
||||||
|
var swap_chain_format: gpu.Texture.Format = undefined;
|
||||||
|
var surface: ?gpu.Surface = null;
|
||||||
|
if (!use_legacy_api) {
|
||||||
|
swap_chain_format = .bgra8_unorm;
|
||||||
|
descriptor = .{
|
||||||
|
.label = "basic swap chain",
|
||||||
|
.usage = .{ .render_attachment = true },
|
||||||
|
.format = swap_chain_format,
|
||||||
|
.width = framebuffer_size.width,
|
||||||
|
.height = framebuffer_size.height,
|
||||||
|
.present_mode = switch (options.vsync) {
|
||||||
|
.none => .immediate,
|
||||||
|
.double => .fifo,
|
||||||
|
.triple => .mailbox,
|
||||||
|
},
|
||||||
|
.implementation = 0,
|
||||||
|
};
|
||||||
|
surface = util.createSurfaceForWindow(
|
||||||
|
&native_instance,
|
||||||
|
window,
|
||||||
|
comptime util.detectGLFWOptions(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const binding = c.machUtilsCreateBinding(@enumToInt(backend_type), @ptrCast(*c.GLFWwindow, window.handle), @ptrCast(c.WGPUDevice, device.ptr));
|
||||||
|
if (binding == null) {
|
||||||
|
@panic("failed to create Dawn backend binding");
|
||||||
|
}
|
||||||
|
descriptor = std.mem.zeroes(gpu.SwapChain.Descriptor);
|
||||||
|
descriptor.implementation = c.machUtilsBackendBinding_getSwapChainImplementation(binding);
|
||||||
|
swap_chain = device.nativeCreateSwapChain(null, &descriptor);
|
||||||
|
|
||||||
|
swap_chain_format = @intToEnum(gpu.Texture.Format, @intCast(u32, c.machUtilsBackendBinding_getPreferredSwapChainTextureFormat(binding)));
|
||||||
|
swap_chain.?.configure(
|
||||||
|
swap_chain_format,
|
||||||
|
.{ .render_attachment = true },
|
||||||
|
framebuffer_size.width,
|
||||||
|
framebuffer_size.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
device.setUncapturedErrorCallback(&util.printUnhandledErrorCallback);
|
||||||
|
|
||||||
|
engine.device = device;
|
||||||
|
engine.backend_type = backend_type;
|
||||||
|
engine.surface = surface;
|
||||||
|
engine.swap_chain = swap_chain;
|
||||||
|
engine.swap_chain_format = swap_chain_format;
|
||||||
|
engine.current_desc = descriptor;
|
||||||
|
engine.target_desc = descriptor;
|
||||||
|
|
||||||
|
return Platform{
|
||||||
.window = window,
|
.window = window,
|
||||||
.backend_type = backend_type,
|
.backend_type = backend_type,
|
||||||
.allocator = engine.allocator,
|
.allocator = engine.allocator,
|
||||||
.last_window_size = .{ .width = window_size.width, .height = window_size.height },
|
.last_window_size = .{ .width = window_size.width, .height = window_size.height },
|
||||||
.last_framebuffer_size = .{ .width = framebuffer_size.width, .height = framebuffer_size.height },
|
.last_framebuffer_size = .{ .width = framebuffer_size.width, .height = framebuffer_size.height },
|
||||||
|
.native_instance = native_instance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pushEvent(self: *Core, event: structs.Event) void {
|
fn pushEvent(platform: *Platform, event: structs.Event) void {
|
||||||
const node = self.allocator.create(EventNode) catch unreachable;
|
const node = platform.allocator.create(EventNode) catch unreachable;
|
||||||
node.* = .{ .data = event };
|
node.* = .{ .data = event };
|
||||||
self.events.append(node);
|
platform.events.append(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initCallback(self: *Core) void {
|
fn initCallback(platform: *Platform) void {
|
||||||
self.user_ptr = UserPtr{ .core = self };
|
platform.user_ptr = UserPtr{ .platform = platform };
|
||||||
|
|
||||||
self.window.setUserPointer(&self.user_ptr);
|
platform.window.setUserPointer(&platform.user_ptr);
|
||||||
|
|
||||||
const callback = struct {
|
const callback = struct {
|
||||||
fn callback(window: glfw.Window, key: glfw.Key, scancode: i32, action: glfw.Action, mods: glfw.Mods) void {
|
fn callback(window: glfw.Window, key: glfw.Key, scancode: i32, action: glfw.Action, mods: glfw.Mods) void {
|
||||||
const core = (window.getUserPointer(UserPtr) orelse unreachable).core;
|
const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
.press => core.pushEvent(.{
|
.press => pf.pushEvent(.{
|
||||||
.key_press = .{
|
.key_press = .{
|
||||||
.key = toMachKey(key),
|
.key = toMachKey(key),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
.release => core.pushEvent(.{
|
.release => pf.pushEvent(.{
|
||||||
.key_release = .{
|
.key_release = .{
|
||||||
.key = toMachKey(key),
|
.key = toMachKey(key),
|
||||||
},
|
},
|
||||||
|
|
@ -89,49 +214,49 @@ pub const Core = struct {
|
||||||
_ = mods;
|
_ = mods;
|
||||||
}
|
}
|
||||||
}.callback;
|
}.callback;
|
||||||
self.window.setKeyCallback(callback);
|
platform.window.setKeyCallback(callback);
|
||||||
|
|
||||||
const size_callback = struct {
|
const size_callback = struct {
|
||||||
fn callback(window: glfw.Window, width: i32, height: i32) void {
|
fn callback(window: glfw.Window, width: i32, height: i32) void {
|
||||||
const core = (window.getUserPointer(UserPtr) orelse unreachable).core;
|
const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform;
|
||||||
core.last_window_size.width = @intCast(u32, width);
|
pf.last_window_size.width = @intCast(u32, width);
|
||||||
core.last_window_size.height = @intCast(u32, height);
|
pf.last_window_size.height = @intCast(u32, height);
|
||||||
}
|
}
|
||||||
}.callback;
|
}.callback;
|
||||||
self.window.setSizeCallback(size_callback);
|
platform.window.setSizeCallback(size_callback);
|
||||||
|
|
||||||
const framebuffer_size_callback = struct {
|
const framebuffer_size_callback = struct {
|
||||||
fn callback(window: glfw.Window, width: u32, height: u32) void {
|
fn callback(window: glfw.Window, width: u32, height: u32) void {
|
||||||
const core = (window.getUserPointer(UserPtr) orelse unreachable).core;
|
const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform;
|
||||||
core.last_framebuffer_size.width = width;
|
pf.last_framebuffer_size.width = width;
|
||||||
core.last_framebuffer_size.height = height;
|
pf.last_framebuffer_size.height = height;
|
||||||
}
|
}
|
||||||
}.callback;
|
}.callback;
|
||||||
self.window.setFramebufferSizeCallback(framebuffer_size_callback);
|
platform.window.setFramebufferSizeCallback(framebuffer_size_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setShouldClose(self: *Core, value: bool) void {
|
pub fn setShouldClose(platform: *Platform, value: bool) void {
|
||||||
self.window.setShouldClose(value);
|
platform.window.setShouldClose(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getFramebufferSize(self: *Core) structs.Size {
|
pub fn getFramebufferSize(platform: *Platform) structs.Size {
|
||||||
return self.last_framebuffer_size;
|
return platform.last_framebuffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWindowSize(self: *Core) structs.Size {
|
pub fn getWindowSize(platform: *Platform) structs.Size {
|
||||||
return self.last_window_size;
|
return platform.last_window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSizeLimits(self: *Core, min: structs.SizeOptional, max: structs.SizeOptional) !void {
|
pub fn setSizeLimits(platform: *Platform, min: structs.SizeOptional, max: structs.SizeOptional) !void {
|
||||||
try self.window.setSizeLimits(
|
try platform.window.setSizeLimits(
|
||||||
@bitCast(glfw.Window.SizeOptional, min),
|
@bitCast(glfw.Window.SizeOptional, min),
|
||||||
@bitCast(glfw.Window.SizeOptional, max),
|
@bitCast(glfw.Window.SizeOptional, max),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pollEvent(self: *Core) ?structs.Event {
|
pub fn pollEvent(platform: *Platform) ?structs.Event {
|
||||||
if (self.events.popFirst()) |n| {
|
if (platform.events.popFirst()) |n| {
|
||||||
defer self.allocator.destroy(n);
|
defer platform.allocator.destroy(n);
|
||||||
return n.data;
|
return n.data;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -274,144 +399,6 @@ pub const Core = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GpuDriver = struct {
|
|
||||||
native_instance: gpu.NativeInstance,
|
|
||||||
|
|
||||||
pub fn init(_: std.mem.Allocator, engine: *Engine) !GpuDriver {
|
|
||||||
const options = engine.options;
|
|
||||||
const window = engine.core.internal.window;
|
|
||||||
const backend_type = engine.core.internal.backend_type;
|
|
||||||
|
|
||||||
const backend_procs = c.machDawnNativeGetProcs();
|
|
||||||
c.dawnProcSetProcs(backend_procs);
|
|
||||||
|
|
||||||
const instance = c.machDawnNativeInstance_init();
|
|
||||||
var native_instance = gpu.NativeInstance.wrap(c.machDawnNativeInstance_get(instance).?);
|
|
||||||
|
|
||||||
// Discover e.g. OpenGL adapters.
|
|
||||||
try util.discoverAdapters(instance, window, backend_type);
|
|
||||||
|
|
||||||
// Request an adapter.
|
|
||||||
//
|
|
||||||
// TODO: It would be nice if we could use gpu_interface.waitForAdapter here, however the webgpu.h
|
|
||||||
// API does not yet have a way to specify what type of backend you want (vulkan, opengl, etc.)
|
|
||||||
// In theory, I suppose we shouldn't need to and Dawn should just pick the best adapter - but in
|
|
||||||
// practice if Vulkan is not supported today waitForAdapter/requestAdapter merely generates an error.
|
|
||||||
//
|
|
||||||
// const gpu_interface = native_instance.interface();
|
|
||||||
// const backend_adapter = switch (gpu_interface.waitForAdapter(&.{
|
|
||||||
// .power_preference = .high_performance,
|
|
||||||
// })) {
|
|
||||||
// .adapter => |v| v,
|
|
||||||
// .err => |err| {
|
|
||||||
// std.debug.print("mach: failed to get adapter: error={} {s}\n", .{ err.code, err.message });
|
|
||||||
// std.process.exit(1);
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
const adapters = c.machDawnNativeInstance_getAdapters(instance);
|
|
||||||
var dawn_adapter: ?c.MachDawnNativeAdapter = null;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < c.machDawnNativeAdapters_length(adapters)) : (i += 1) {
|
|
||||||
const adapter = c.machDawnNativeAdapters_index(adapters, i);
|
|
||||||
const properties = c.machDawnNativeAdapter_getProperties(adapter);
|
|
||||||
const found_backend_type = @intToEnum(gpu.Adapter.BackendType, c.machDawnNativeAdapterProperties_getBackendType(properties));
|
|
||||||
if (found_backend_type == backend_type) {
|
|
||||||
dawn_adapter = adapter;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dawn_adapter == null) {
|
|
||||||
std.debug.print("mach: no matching adapter found for {s}", .{@tagName(backend_type)});
|
|
||||||
std.debug.print("-> maybe try GPU_BACKEND=opengl ?\n", .{});
|
|
||||||
std.process.exit(1);
|
|
||||||
}
|
|
||||||
std.debug.assert(dawn_adapter != null);
|
|
||||||
const backend_adapter = gpu.NativeInstance.fromWGPUAdapter(c.machDawnNativeAdapter_get(dawn_adapter.?).?);
|
|
||||||
|
|
||||||
// Print which adapter we are going to use.
|
|
||||||
const props = backend_adapter.properties;
|
|
||||||
std.debug.print("mach: found {s} backend on {s} adapter: {s}, {s}\n", .{
|
|
||||||
gpu.Adapter.backendTypeName(props.backend_type),
|
|
||||||
gpu.Adapter.typeName(props.adapter_type),
|
|
||||||
props.name,
|
|
||||||
props.driver_description,
|
|
||||||
});
|
|
||||||
|
|
||||||
const device = switch (backend_adapter.waitForDevice(&.{
|
|
||||||
.required_features = options.required_features,
|
|
||||||
.required_limits = options.required_limits,
|
|
||||||
})) {
|
|
||||||
.device => |v| v,
|
|
||||||
.err => |err| {
|
|
||||||
// TODO: return a proper error type
|
|
||||||
std.debug.print("mach: failed to get device: error={} {s}\n", .{ err.code, err.message });
|
|
||||||
std.process.exit(1);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var framebuffer_size = engine.core.getFramebufferSize();
|
|
||||||
|
|
||||||
// If targeting OpenGL, we can't use the newer WGPUSurface API. Instead, we need to use the
|
|
||||||
// older Dawn-specific API. https://bugs.chromium.org/p/dawn/issues/detail?id=269&q=surface&can=2
|
|
||||||
const use_legacy_api = backend_type == .opengl or backend_type == .opengles;
|
|
||||||
var descriptor: gpu.SwapChain.Descriptor = undefined;
|
|
||||||
var swap_chain: ?gpu.SwapChain = null;
|
|
||||||
var swap_chain_format: gpu.Texture.Format = undefined;
|
|
||||||
var surface: ?gpu.Surface = null;
|
|
||||||
if (!use_legacy_api) {
|
|
||||||
swap_chain_format = .bgra8_unorm;
|
|
||||||
descriptor = .{
|
|
||||||
.label = "basic swap chain",
|
|
||||||
.usage = .{ .render_attachment = true },
|
|
||||||
.format = swap_chain_format,
|
|
||||||
.width = framebuffer_size.width,
|
|
||||||
.height = framebuffer_size.height,
|
|
||||||
.present_mode = switch (options.vsync) {
|
|
||||||
.none => .immediate,
|
|
||||||
.double => .fifo,
|
|
||||||
.triple => .mailbox,
|
|
||||||
},
|
|
||||||
.implementation = 0,
|
|
||||||
};
|
|
||||||
surface = util.createSurfaceForWindow(
|
|
||||||
&native_instance,
|
|
||||||
window,
|
|
||||||
comptime util.detectGLFWOptions(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const binding = c.machUtilsCreateBinding(@enumToInt(backend_type), @ptrCast(*c.GLFWwindow, window.handle), @ptrCast(c.WGPUDevice, device.ptr));
|
|
||||||
if (binding == null) {
|
|
||||||
@panic("failed to create Dawn backend binding");
|
|
||||||
}
|
|
||||||
descriptor = std.mem.zeroes(gpu.SwapChain.Descriptor);
|
|
||||||
descriptor.implementation = c.machUtilsBackendBinding_getSwapChainImplementation(binding);
|
|
||||||
swap_chain = device.nativeCreateSwapChain(null, &descriptor);
|
|
||||||
|
|
||||||
swap_chain_format = @intToEnum(gpu.Texture.Format, @intCast(u32, c.machUtilsBackendBinding_getPreferredSwapChainTextureFormat(binding)));
|
|
||||||
swap_chain.?.configure(
|
|
||||||
swap_chain_format,
|
|
||||||
.{ .render_attachment = true },
|
|
||||||
framebuffer_size.width,
|
|
||||||
framebuffer_size.height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
device.setUncapturedErrorCallback(&util.printUnhandledErrorCallback);
|
|
||||||
|
|
||||||
engine.gpu_driver.device = device;
|
|
||||||
engine.gpu_driver.backend_type = backend_type;
|
|
||||||
engine.gpu_driver.surface = surface;
|
|
||||||
engine.gpu_driver.swap_chain = swap_chain;
|
|
||||||
engine.gpu_driver.swap_chain_format = swap_chain_format;
|
|
||||||
engine.gpu_driver.current_desc = descriptor;
|
|
||||||
engine.gpu_driver.target_desc = descriptor;
|
|
||||||
|
|
||||||
return GpuDriver{
|
|
||||||
.native_instance = native_instance,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const BackingTimer = std.time.Timer;
|
pub const BackingTimer = std.time.Timer;
|
||||||
|
|
||||||
const common = @import("common.zig");
|
const common = @import("common.zig");
|
||||||
|
|
@ -431,34 +418,34 @@ pub fn main() !void {
|
||||||
defer app.deinit(&engine);
|
defer app.deinit(&engine);
|
||||||
|
|
||||||
// Glfw specific: initialize the user pointer used in callbacks
|
// Glfw specific: initialize the user pointer used in callbacks
|
||||||
engine.core.internal.initCallback();
|
engine.internal.initCallback();
|
||||||
|
|
||||||
const window = engine.core.internal.window;
|
const window = engine.internal.window;
|
||||||
while (!window.shouldClose()) {
|
while (!window.shouldClose()) {
|
||||||
try glfw.pollEvents();
|
try glfw.pollEvents();
|
||||||
|
|
||||||
engine.delta_time_ns = engine.timer.lapPrecise();
|
engine.delta_time_ns = engine.timer.lapPrecise();
|
||||||
engine.delta_time = @intToFloat(f32, engine.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s);
|
engine.delta_time = @intToFloat(f32, engine.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s);
|
||||||
|
|
||||||
var framebuffer_size = engine.core.getFramebufferSize();
|
var framebuffer_size = engine.getFramebufferSize();
|
||||||
engine.gpu_driver.target_desc.width = framebuffer_size.width;
|
engine.target_desc.width = framebuffer_size.width;
|
||||||
engine.gpu_driver.target_desc.height = framebuffer_size.height;
|
engine.target_desc.height = framebuffer_size.height;
|
||||||
|
|
||||||
if (engine.gpu_driver.swap_chain == null or !engine.gpu_driver.current_desc.equal(&engine.gpu_driver.target_desc)) {
|
if (engine.swap_chain == null or !engine.current_desc.equal(&engine.target_desc)) {
|
||||||
const use_legacy_api = engine.gpu_driver.surface == null;
|
const use_legacy_api = engine.surface == null;
|
||||||
if (!use_legacy_api) {
|
if (!use_legacy_api) {
|
||||||
engine.gpu_driver.swap_chain = engine.gpu_driver.device.nativeCreateSwapChain(engine.gpu_driver.surface, &engine.gpu_driver.target_desc);
|
engine.swap_chain = engine.device.nativeCreateSwapChain(engine.surface, &engine.target_desc);
|
||||||
} else engine.gpu_driver.swap_chain.?.configure(
|
} else engine.swap_chain.?.configure(
|
||||||
engine.gpu_driver.swap_chain_format,
|
engine.swap_chain_format,
|
||||||
.{ .render_attachment = true },
|
.{ .render_attachment = true },
|
||||||
engine.gpu_driver.target_desc.width,
|
engine.target_desc.width,
|
||||||
engine.gpu_driver.target_desc.height,
|
engine.target_desc.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (@hasDecl(App, "resize")) {
|
if (@hasDecl(App, "resize")) {
|
||||||
try app.resize(&engine, engine.gpu_driver.target_desc.width, engine.gpu_driver.target_desc.height);
|
try app.resize(&engine, engine.target_desc.width, engine.target_desc.height);
|
||||||
}
|
}
|
||||||
engine.gpu_driver.current_desc = engine.gpu_driver.target_desc;
|
engine.current_desc = engine.target_desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const success = try app.update(&engine);
|
const success = try app.update(&engine);
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ const js = struct {
|
||||||
|
|
||||||
pub const CanvasId = u32;
|
pub const CanvasId = u32;
|
||||||
|
|
||||||
pub const Core = struct {
|
pub const Platform = struct {
|
||||||
id: CanvasId,
|
id: CanvasId,
|
||||||
selector_id: []const u8,
|
selector_id: []const u8,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, eng: *Engine) !Core {
|
pub fn init(allocator: std.mem.Allocator, eng: *Engine) !Platform {
|
||||||
const options = eng.options;
|
const options = eng.options;
|
||||||
var selector = [1]u8{0} ** 15;
|
var selector = [1]u8{0} ** 15;
|
||||||
const id = js.machCanvasInit(options.width, options.height, &selector[0]);
|
const id = js.machCanvasInit(options.width, options.height, &selector[0]);
|
||||||
|
|
@ -36,31 +36,31 @@ pub const Core = struct {
|
||||||
const title = std.mem.span(options.title);
|
const title = std.mem.span(options.title);
|
||||||
js.machCanvasSetTitle(id, title.ptr, title.len);
|
js.machCanvasSetTitle(id, title.ptr, title.len);
|
||||||
|
|
||||||
return Core{
|
return Platform{
|
||||||
.id = id,
|
.id = id,
|
||||||
.selector_id = try allocator.dupe(u8, selector[0 .. selector.len - @as(u32, if (selector[selector.len - 1] == 0) 1 else 0)]),
|
.selector_id = try allocator.dupe(u8, selector[0 .. selector.len - @as(u32, if (selector[selector.len - 1] == 0) 1 else 0)]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setShouldClose(_: *Core, _: bool) void {}
|
pub fn setShouldClose(_: *Platform, _: bool) void {}
|
||||||
|
|
||||||
pub fn getFramebufferSize(core: *Core) structs.Size {
|
pub fn getFramebufferSize(platform: *Platform) structs.Size {
|
||||||
return structs.Size{
|
return structs.Size{
|
||||||
.width = js.machCanvasGetFramebufferWidth(core.id),
|
.width = js.machCanvasGetFramebufferWidth(platform.id),
|
||||||
.height = js.machCanvasGetFramebufferHeight(core.id),
|
.height = js.machCanvasGetFramebufferHeight(platform.id),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWindowSize(core: *Core) structs.Size {
|
pub fn getWindowSize(platform: *Platform) structs.Size {
|
||||||
return structs.Size{
|
return structs.Size{
|
||||||
.width = js.machCanvasGetWindowWidth(core.id),
|
.width = js.machCanvasGetWindowWidth(platform.id),
|
||||||
.height = js.machCanvasGetWindowHeight(core.id),
|
.height = js.machCanvasGetWindowHeight(platform.id),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSizeLimits(_: *Core, _: structs.SizeOptional, _: structs.SizeOptional) !void {}
|
pub fn setSizeLimits(_: *Platform, _: structs.SizeOptional, _: structs.SizeOptional) !void {}
|
||||||
|
|
||||||
pub fn pollEvent(_: *Core) ?structs.Event {
|
pub fn pollEvent(_: *Platform) ?structs.Event {
|
||||||
const event_type = js.machEventShift();
|
const event_type = js.machEventShift();
|
||||||
|
|
||||||
return switch (event_type) {
|
return switch (event_type) {
|
||||||
|
|
@ -75,12 +75,6 @@ pub const Core = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GpuDriver = struct {
|
|
||||||
pub fn init(_: std.mem.Allocator, _: *Engine) !GpuDriver {
|
|
||||||
return GpuDriver{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const BackingTimer = struct {
|
pub const BackingTimer = struct {
|
||||||
initial: f64 = undefined,
|
initial: f64 = undefined,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue