gpu: make requestAdapter callback-based, add waitForAdapter helper

Same rationale as 2c3e13ff4b90886d7f03adb3103abc9dee70b407

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2022-03-15 11:02:51 -07:00 committed by Stephen Gutekanst
parent aab99b5474
commit 356e4102cd
5 changed files with 71 additions and 40 deletions

View file

@ -73,7 +73,7 @@ pub fn setup(allocator: std.mem.Allocator) !Setup {
try discoverAdapters(instance, window, backend_type); try discoverAdapters(instance, window, backend_type);
// Request an adapter. // Request an adapter.
const backend_adapter = switch (nosuspend gpu_interface.requestAdapter(&.{ const backend_adapter = switch (gpu_interface.waitForAdapter(&.{
.power_preference = .high_performance, .power_preference = .high_performance,
})) { })) {
.adapter => |v| v, .adapter => |v| v,

View file

@ -204,4 +204,5 @@ test "syntax" {
_ = RequestDeviceResponse; _ = RequestDeviceResponse;
_ = RequestDeviceCallback; _ = RequestDeviceCallback;
_ = requestDevice; _ = requestDevice;
_ = waitForDevice;
} }

View file

@ -13,13 +13,14 @@ const Interface = @This();
ptr: *anyopaque, ptr: *anyopaque,
vtable: *const VTable, vtable: *const VTable,
// The @frameSize(func) of the implementations requestAdapter async function
request_adapter_frame_size: usize,
pub const VTable = struct { pub const VTable = struct {
reference: fn (ptr: *anyopaque) void, reference: fn (ptr: *anyopaque) void,
release: 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 { pub inline fn reference(interface: Interface) void {
@ -59,24 +60,53 @@ pub const RequestAdapterResponse = union(RequestAdapterResponseTag) {
err: RequestAdapterError, err: RequestAdapterError,
}; };
pub fn requestAdapter(interface: Interface, options: *const RequestAdapterOptions) callconv(.Async) RequestAdapterResponse { pub fn requestAdapter(
var frame_buffer = std.heap.page_allocator.allocAdvanced( interface: Interface,
u8, options: *const RequestAdapterOptions,
16, callback: *RequestAdapterCallback,
interface.request_adapter_frame_size, ) void {
std.mem.Allocator.Exact.at_least, interface.vtable.requestAdapter(interface.ptr, options, callback);
) catch { }
return .{ .err = .{
.message = "Out of memory",
.code = RequestAdapterErrorCode.Error,
} };
};
defer std.heap.page_allocator.free(frame_buffer);
var result: RequestAdapterResponse = undefined; pub const RequestAdapterCallback = struct {
const f = @asyncCall(frame_buffer, &result, interface.vtable.requestAdapter, .{ interface.ptr, options }); type_erased_ctx: *anyopaque,
resume f; type_erased_callback: fn (ctx: *anyopaque, response: RequestAdapterResponse) callconv(.Inline) void,
return result;
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" { test "syntax" {
@ -88,4 +118,5 @@ test "syntax" {
_ = RequestAdapterError; _ = RequestAdapterError;
_ = RequestAdapterResponse; _ = RequestAdapterResponse;
_ = requestAdapter; _ = requestAdapter;
_ = waitForAdapter;
} }

View file

@ -6,13 +6,14 @@ const Interface = @import("Interface.zig");
const RequestAdapterOptions = Interface.RequestAdapterOptions; const RequestAdapterOptions = Interface.RequestAdapterOptions;
const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode; const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode;
const RequestAdapterError = Interface.RequestAdapterError; const RequestAdapterError = Interface.RequestAdapterError;
const RequestAdapterCallback = Interface.RequestAdapterCallback;
const RequestAdapterResponse = Interface.RequestAdapterResponse; const RequestAdapterResponse = Interface.RequestAdapterResponse;
const Adapter = @import("Adapter.zig"); const Adapter = @import("Adapter.zig");
const RequestDeviceErrorCode = Adapter.RequestDeviceErrorCode; const RequestDeviceErrorCode = Adapter.RequestDeviceErrorCode;
const RequestDeviceError = Adapter.RequestDeviceError; const RequestDeviceError = Adapter.RequestDeviceError;
const RequestDeviceResponse = Adapter.RequestDeviceResponse;
const RequestDeviceCallback = Adapter.RequestDeviceCallback; const RequestDeviceCallback = Adapter.RequestDeviceCallback;
const RequestDeviceResponse = Adapter.RequestDeviceResponse;
const Device = @import("Device.zig"); const Device = @import("Device.zig");
const Surface = @import("Surface.zig"); const Surface = @import("Surface.zig");
@ -64,7 +65,11 @@ const interface_vtable = Interface.VTable{
} }
}).release, }).release,
.requestAdapter = (struct { .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 native = @ptrCast(*NativeInstance, @alignCast(@alignOf(*NativeInstance), ptr));
const opt = c.WGPURequestAdapterOptions{ const opt = c.WGPURequestAdapterOptions{
@ -74,14 +79,14 @@ const interface_vtable = Interface.VTable{
.forceFallbackAdapter = options.force_fallback_adapter, .forceFallbackAdapter = options.force_fallback_adapter,
}; };
const callback = (struct { const cCallback = (struct {
pub fn callback(status: c.WGPURequestAdapterStatus, adapter: c.WGPUAdapter, message: [*c]const u8, userdata: ?*anyopaque) callconv(.C) void { pub fn cCallback(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 callback_info = @ptrCast(*RequestAdapterCallback, @alignCast(@alignOf(*RequestAdapterCallback), userdata.?));
// Store the response into a field on the native instance for later reading. // 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.?), .adapter = wrapAdapter(adapter.?),
} else .{ } else RequestAdapterResponse{
.err = Interface.RequestAdapterError{ .err = Interface.RequestAdapterError{
.message = std.mem.span(message), .message = std.mem.span(message),
.code = switch (status) { .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, cCallback, callback);
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;
} }
}).requestAdapter, }).requestAdapter,
}; };
@ -113,7 +112,6 @@ pub fn interface(native: *NativeInstance) Interface {
return .{ return .{
.ptr = native, .ptr = native,
.vtable = &interface_vtable, .vtable = &interface_vtable,
.request_adapter_frame_size = @frameSize(interface_vtable.requestAdapter),
}; };
} }

View file

@ -47,6 +47,7 @@ pub const Interface = @import("Interface.zig");
pub const RequestAdapterOptions = Interface.RequestAdapterOptions; pub const RequestAdapterOptions = Interface.RequestAdapterOptions;
pub const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode; pub const RequestAdapterErrorCode = Interface.RequestAdapterErrorCode;
pub const RequestAdapterError = Interface.RequestAdapterError; pub const RequestAdapterError = Interface.RequestAdapterError;
pub const RequestAdapterCallback = Interface.RequestAdapterCallback;
pub const RequestAdapterResponse = Interface.RequestAdapterResponse; pub const RequestAdapterResponse = Interface.RequestAdapterResponse;
pub const Adapter = @import("Adapter.zig"); pub const Adapter = @import("Adapter.zig");