diff --git a/gpu/examples/sample_utils.zig b/gpu/examples/sample_utils.zig index 574d4b4f..c9c75069 100644 --- a/gpu/examples/sample_utils.zig +++ b/gpu/examples/sample_utils.zig @@ -73,7 +73,7 @@ pub fn setup(allocator: std.mem.Allocator) !Setup { try discoverAdapters(instance, window, backend_type); // Request an adapter. - const backend_adapter = switch (nosuspend gpu_interface.requestAdapter(&.{ + const backend_adapter = switch (gpu_interface.waitForAdapter(&.{ .power_preference = .high_performance, })) { .adapter => |v| v, diff --git a/gpu/src/Adapter.zig b/gpu/src/Adapter.zig index 3ea0d3f9..ccbafcf6 100644 --- a/gpu/src/Adapter.zig +++ b/gpu/src/Adapter.zig @@ -204,4 +204,5 @@ test "syntax" { _ = RequestDeviceResponse; _ = RequestDeviceCallback; _ = requestDevice; + _ = waitForDevice; } diff --git a/gpu/src/Interface.zig b/gpu/src/Interface.zig index d0db1d55..23f3cac1 100644 --- a/gpu/src/Interface.zig +++ b/gpu/src/Interface.zig @@ -13,13 +13,14 @@ const Interface = @This(); ptr: *anyopaque, vtable: *const VTable, -// The @frameSize(func) of the implementations requestAdapter async function -request_adapter_frame_size: usize, - pub const VTable = struct { reference: fn (ptr: *anyopaque) void, release: fn (ptr: *anyopaque) void, - requestAdapter: fn requestAdapter(ptr: *anyopaque, options: *const RequestAdapterOptions) callconv(.Async) RequestAdapterResponse, + requestAdapter: fn requestAdapter( + ptr: *anyopaque, + options: *const RequestAdapterOptions, + callback: *RequestAdapterCallback, + ) void, }; pub inline fn reference(interface: Interface) void { @@ -59,24 +60,53 @@ pub const RequestAdapterResponse = union(RequestAdapterResponseTag) { err: RequestAdapterError, }; -pub fn requestAdapter(interface: Interface, options: *const RequestAdapterOptions) callconv(.Async) RequestAdapterResponse { - var frame_buffer = std.heap.page_allocator.allocAdvanced( - u8, - 16, - interface.request_adapter_frame_size, - std.mem.Allocator.Exact.at_least, - ) catch { - return .{ .err = .{ - .message = "Out of memory", - .code = RequestAdapterErrorCode.Error, - } }; - }; - defer std.heap.page_allocator.free(frame_buffer); +pub fn requestAdapter( + interface: Interface, + options: *const RequestAdapterOptions, + callback: *RequestAdapterCallback, +) void { + interface.vtable.requestAdapter(interface.ptr, options, callback); +} - var result: RequestAdapterResponse = undefined; - const f = @asyncCall(frame_buffer, &result, interface.vtable.requestAdapter, .{ interface.ptr, options }); - resume f; - return result; +pub const RequestAdapterCallback = struct { + type_erased_ctx: *anyopaque, + type_erased_callback: fn (ctx: *anyopaque, response: RequestAdapterResponse) callconv(.Inline) void, + + pub fn init( + comptime Context: type, + ctx: *Context, + comptime callback: fn (ctx: *Context, response: RequestAdapterResponse) void, + ) RequestAdapterCallback { + const erased = (struct { + pub inline fn erased(type_erased_ctx: *anyopaque, response: RequestAdapterResponse) void { + callback(@ptrCast(*Context, @alignCast(@alignOf(*Context), type_erased_ctx)), response); + } + }).erased; + + return .{ + .type_erased_ctx = ctx, + .type_erased_callback = erased, + }; + } +}; + +/// A helper which invokes requestAdapter and blocks until the adapter is recieved. +pub fn waitForAdapter(interface: Interface, options: *const RequestAdapterOptions) RequestAdapterResponse { + const Context = RequestAdapterResponse; + var response: Context = undefined; + var callback = RequestAdapterCallback.init(Context, &response, (struct { + pub fn callback(ctx: *Context, callback_response: RequestAdapterResponse) void { + ctx.* = callback_response; + } + }).callback); + + interface.requestAdapter(options, &callback); + + // TODO: FUTURE: Once crbug.com/dawn/1122 is fixed, we should process events here otherwise our + // callback would not be invoked: + //c.wgpuInstanceProcessEvents(interface.instance) + + return response; } test "syntax" { @@ -88,4 +118,5 @@ test "syntax" { _ = RequestAdapterError; _ = RequestAdapterResponse; _ = requestAdapter; + _ = waitForAdapter; } diff --git a/gpu/src/NativeInstance.zig b/gpu/src/NativeInstance.zig index d5ed36a9..4f9c5a7e 100644 --- a/gpu/src/NativeInstance.zig +++ b/gpu/src/NativeInstance.zig @@ -6,13 +6,14 @@ const Interface = @import("Interface.zig"); const RequestAdapterOptions = Interface.RequestAdapterOptions; const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode; const RequestAdapterError = Interface.RequestAdapterError; +const RequestAdapterCallback = Interface.RequestAdapterCallback; const RequestAdapterResponse = Interface.RequestAdapterResponse; const Adapter = @import("Adapter.zig"); const RequestDeviceErrorCode = Adapter.RequestDeviceErrorCode; const RequestDeviceError = Adapter.RequestDeviceError; -const RequestDeviceResponse = Adapter.RequestDeviceResponse; const RequestDeviceCallback = Adapter.RequestDeviceCallback; +const RequestDeviceResponse = Adapter.RequestDeviceResponse; const Device = @import("Device.zig"); const Surface = @import("Surface.zig"); @@ -64,7 +65,11 @@ const interface_vtable = Interface.VTable{ } }).release, .requestAdapter = (struct { - pub fn requestAdapter(ptr: *anyopaque, options: *const RequestAdapterOptions) callconv(.Async) RequestAdapterResponse { + pub fn requestAdapter( + ptr: *anyopaque, + options: *const RequestAdapterOptions, + callback: *RequestAdapterCallback, + ) void { const native = @ptrCast(*NativeInstance, @alignCast(@alignOf(*NativeInstance), ptr)); const opt = c.WGPURequestAdapterOptions{ @@ -74,14 +79,14 @@ const interface_vtable = Interface.VTable{ .forceFallbackAdapter = options.force_fallback_adapter, }; - const callback = (struct { - pub fn callback(status: c.WGPURequestAdapterStatus, adapter: c.WGPUAdapter, message: [*c]const u8, userdata: ?*anyopaque) callconv(.C) void { - const _callback_response = @ptrCast(*Interface.RequestAdapterResponse, @alignCast(@alignOf(*Interface.RequestAdapterResponse), userdata)); + const cCallback = (struct { + pub fn cCallback(status: c.WGPURequestAdapterStatus, adapter: c.WGPUAdapter, message: [*c]const u8, userdata: ?*anyopaque) callconv(.C) void { + const callback_info = @ptrCast(*RequestAdapterCallback, @alignCast(@alignOf(*RequestAdapterCallback), userdata.?)); // Store the response into a field on the native instance for later reading. - _callback_response.* = if (status == c.WGPURequestAdapterStatus_Success) .{ + const response = if (status == c.WGPURequestAdapterStatus_Success) RequestAdapterResponse{ .adapter = wrapAdapter(adapter.?), - } else .{ + } else RequestAdapterResponse{ .err = Interface.RequestAdapterError{ .message = std.mem.span(message), .code = switch (status) { @@ -92,18 +97,12 @@ const interface_vtable = Interface.VTable{ }, }, }; + + callback_info.type_erased_callback(callback_info.type_erased_ctx, response); } - }).callback; + }).cCallback; - var callback_response: Interface.RequestAdapterResponse = undefined; - c.wgpuInstanceRequestAdapter(native.instance, &opt, callback, &callback_response); - // TODO: Once crbug.com/dawn/1122 is fixed, we should process events here otherwise our - // callback will not be invoked. - // c.wgpuInstanceProcessEvents(native.instance) - suspend {} // must suspend so that async caller can resume - - // Return the response, asserting the callback has executed at this point. - return callback_response; + c.wgpuInstanceRequestAdapter(native.instance, &opt, cCallback, callback); } }).requestAdapter, }; @@ -113,7 +112,6 @@ pub fn interface(native: *NativeInstance) Interface { return .{ .ptr = native, .vtable = &interface_vtable, - .request_adapter_frame_size = @frameSize(interface_vtable.requestAdapter), }; } diff --git a/gpu/src/main.zig b/gpu/src/main.zig index e5e4bc25..aec48fdd 100644 --- a/gpu/src/main.zig +++ b/gpu/src/main.zig @@ -47,6 +47,7 @@ pub const Interface = @import("Interface.zig"); pub const RequestAdapterOptions = Interface.RequestAdapterOptions; pub const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode; pub const RequestAdapterError = Interface.RequestAdapterError; +pub const RequestAdapterCallback = Interface.RequestAdapterCallback; pub const RequestAdapterResponse = Interface.RequestAdapterResponse; pub const Adapter = @import("Adapter.zig");