diff --git a/gpu/examples/sample_utils.zig b/gpu/examples/sample_utils.zig index abcfa907..574d4b4f 100644 --- a/gpu/examples/sample_utils.zig +++ b/gpu/examples/sample_utils.zig @@ -92,7 +92,7 @@ pub fn setup(allocator: std.mem.Allocator) !Setup { props.driver_description, }); - const device = switch (nosuspend backend_adapter.requestDevice(&.{})) { + const device = switch (backend_adapter.waitForDevice(&.{})) { .device => |v| v, .err => |err| { std.debug.print("failed to get device: error={} {s}\n", .{ err.code, err.message }); diff --git a/gpu/src/Adapter.zig b/gpu/src/Adapter.zig index 8c5ac474..3ea0d3f9 100644 --- a/gpu/src/Adapter.zig +++ b/gpu/src/Adapter.zig @@ -49,13 +49,14 @@ properties: Properties, ptr: *anyopaque, vtable: *const VTable, -// The @frameSize(func) of the implementations requestDevice async function -request_device_frame_size: usize, - pub const VTable = struct { reference: fn (ptr: *anyopaque) void, release: fn (ptr: *anyopaque) void, - requestDevice: fn requestDevice(ptr: *anyopaque, descriptor: *const Device.Descriptor) callconv(.Async) RequestDeviceResponse, + requestDevice: fn requestDevice( + ptr: *anyopaque, + descriptor: *const Device.Descriptor, + callback: *RequestDeviceCallback, + ) void, }; pub inline fn reference(adapter: Adapter) void { @@ -143,24 +144,53 @@ pub const RequestDeviceResponse = union(RequestDeviceResponseTag) { err: RequestDeviceError, }; -pub fn requestDevice(adapter: Adapter, descriptor: *const Device.Descriptor) callconv(.Async) RequestDeviceResponse { - var frame_buffer = std.heap.page_allocator.allocAdvanced( - u8, - 16, - adapter.request_device_frame_size, - std.mem.Allocator.Exact.at_least, - ) catch { - return .{ .err = .{ - .message = "Out of memory", - .code = RequestDeviceErrorCode.Error, - } }; - }; - defer std.heap.page_allocator.free(frame_buffer); +pub fn requestDevice( + adapter: Adapter, + descriptor: *const Device.Descriptor, + callback: *RequestDeviceCallback, +) void { + adapter.vtable.requestDevice(adapter.ptr, descriptor, callback); +} - var result: RequestDeviceResponse = undefined; - const f = @asyncCall(frame_buffer, &result, adapter.vtable.requestDevice, .{ adapter.ptr, descriptor }); - resume f; - return result; +pub const RequestDeviceCallback = struct { + type_erased_ctx: *anyopaque, + type_erased_callback: fn (ctx: *anyopaque, response: RequestDeviceResponse) callconv(.Inline) void, + + pub fn init( + comptime Context: type, + ctx: *Context, + comptime callback: fn (ctx: *Context, response: RequestDeviceResponse) void, + ) RequestDeviceCallback { + const erased = (struct { + pub inline fn erased(type_erased_ctx: *anyopaque, response: RequestDeviceResponse) 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 requestDevice and blocks until the device is recieved. +pub fn waitForDevice(adapter: Adapter, descriptor: *const Device.Descriptor) RequestDeviceResponse { + const Context = RequestDeviceResponse; + var response: Context = undefined; + var callback = RequestDeviceCallback.init(Context, &response, (struct { + pub fn callback(ctx: *Context, callback_response: RequestDeviceResponse) void { + ctx.* = callback_response; + } + }).callback); + + adapter.requestDevice(descriptor, &callback); + + // TODO: FUTURE: Once crbug.com/dawn/1122 is fixed, we should process events here otherwise our + // callback would not be invoked: + //c.wgpuInstanceProcessEvents(adapter.instance) + + return response; } test "syntax" { @@ -172,5 +202,6 @@ test "syntax" { _ = RequestDeviceErrorCode; _ = RequestDeviceError; _ = RequestDeviceResponse; + _ = RequestDeviceCallback; _ = requestDevice; } diff --git a/gpu/src/NativeInstance.zig b/gpu/src/NativeInstance.zig index fd368052..d5ed36a9 100644 --- a/gpu/src/NativeInstance.zig +++ b/gpu/src/NativeInstance.zig @@ -12,6 +12,7 @@ const Adapter = @import("Adapter.zig"); const RequestDeviceErrorCode = Adapter.RequestDeviceErrorCode; const RequestDeviceError = Adapter.RequestDeviceError; const RequestDeviceResponse = Adapter.RequestDeviceResponse; +const RequestDeviceCallback = Adapter.RequestDeviceCallback; const Device = @import("Device.zig"); const Surface = @import("Surface.zig"); @@ -230,7 +231,6 @@ fn wrapAdapter(adapter: c.WGPUAdapter) Adapter { .ptr = adapter.?, .vtable = &adapter_vtable, - .request_device_frame_size = @frameSize(adapter_vtable.requestDevice), }; } @@ -246,7 +246,11 @@ const adapter_vtable = Adapter.VTable{ } }).release, .requestDevice = (struct { - pub fn requestDevice(ptr: *anyopaque, descriptor: *const Device.Descriptor) callconv(.Async) RequestDeviceResponse { + pub fn requestDevice( + ptr: *anyopaque, + descriptor: *const Device.Descriptor, + callback: *RequestDeviceCallback, + ) void { const adapter = @ptrCast(c.WGPUAdapter, @alignCast(@alignOf(c.WGPUAdapter), ptr)); const required_limits = if (descriptor.required_limits) |l| c.WGPURequiredLimits{ @@ -262,14 +266,13 @@ const adapter_vtable = Adapter.VTable{ .requiredLimits = if (required_limits) |*l| l else null, }; - const callback = (struct { - pub fn callback(status: c.WGPURequestDeviceStatus, device: c.WGPUDevice, message: [*c]const u8, userdata: ?*anyopaque) callconv(.C) void { - const _callback_response = @ptrCast(*Adapter.RequestDeviceResponse, @alignCast(@alignOf(*Adapter.RequestDeviceResponse), userdata)); + const cCallback = (struct { + pub fn cCallback(status: c.WGPURequestDeviceStatus, device: c.WGPUDevice, message: [*c]const u8, userdata: ?*anyopaque) callconv(.C) void { + const callback_info = @ptrCast(*RequestDeviceCallback, @alignCast(@alignOf(*RequestDeviceCallback), userdata.?)); - // Store the response into a field on the native instance for later reading. - _callback_response.* = if (status == c.WGPURequestDeviceStatus_Success) .{ + const response = if (status == c.WGPURequestDeviceStatus_Success) RequestDeviceResponse{ .device = wrapDevice(device.?), - } else .{ + } else RequestDeviceResponse{ .err = Adapter.RequestDeviceError{ .message = std.mem.span(message), .code = switch (status) { @@ -279,18 +282,12 @@ const adapter_vtable = Adapter.VTable{ }, }, }; + + callback_info.type_erased_callback(callback_info.type_erased_ctx, response); } - }).callback; + }).cCallback; - var callback_response: Adapter.RequestDeviceResponse = undefined; - c.wgpuAdapterRequestDevice(adapter, &desc, 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.wgpuAdapterRequestDevice(adapter, &desc, cCallback, callback); } }).requestDevice, }; diff --git a/gpu/src/main.zig b/gpu/src/main.zig index 462de8a6..e5e4bc25 100644 --- a/gpu/src/main.zig +++ b/gpu/src/main.zig @@ -49,10 +49,15 @@ pub const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode; pub const RequestAdapterError = Interface.RequestAdapterError; pub const RequestAdapterResponse = Interface.RequestAdapterResponse; +pub const Adapter = @import("Adapter.zig"); +pub const RequestDeviceErrorCode = Adapter.RequestDeviceErrorCode; +pub const RequestDeviceError = Adapter.RequesatDeviceError; +pub const RequestDeviceCallback = Adapter.RequestDeviceCallback; +pub const RequestDeviceResponse = Adapter.RequestDeviceResponse; + pub const NativeInstance = @import("NativeInstance.zig"); // Interfaces -pub const Adapter = @import("Adapter.zig"); pub const Device = @import("Device.zig"); pub const Surface = @import("Surface.zig"); pub const Queue = @import("Queue.zig");