mach/gpu/src/Interface.zig
PiergiorgioZagaria 169b1e2a42
gpu: correct alignment in pointer casts; handle void Context in all callbacks (#233)
* Fixed ErrorCallback.init() alignment
* Fixed callbacks alignments
* Fixed more of the callback alignment problems
* Added checks for void Context in callback
2022-04-18 11:38:09 -07:00

121 lines
3.5 KiB
Zig

//! A standard interface to a WebGPU implementation.
//!
//! Like std.mem.Allocator, but representing a WebGPU implementation.
const std = @import("std");
const Surface = @import("Surface.zig");
const Adapter = @import("Adapter.zig");
const PowerPreference = @import("enums.zig").PowerPreference;
const Interface = @This();
/// The type erased pointer to the Interface implementation
ptr: *anyopaque,
vtable: *const VTable,
pub const VTable = struct {
reference: fn (ptr: *anyopaque) void,
release: fn (ptr: *anyopaque) void,
requestAdapter: fn requestAdapter(
ptr: *anyopaque,
options: *const RequestAdapterOptions,
callback: *RequestAdapterCallback,
) void,
};
pub inline fn reference(interface: Interface) void {
interface.vtable.reference(interface.ptr);
}
pub inline fn release(interface: Interface) void {
interface.vtable.release(interface.ptr);
}
pub const RequestAdapterOptions = struct {
power_preference: PowerPreference,
force_fallback_adapter: bool = false,
/// Only respected by native WebGPU implementations.
compatible_surface: ?Surface = null,
};
pub const RequestAdapterErrorCode = error{
Unavailable,
Error,
Unknown,
};
pub const RequestAdapterError = struct {
message: []const u8,
code: RequestAdapterErrorCode,
};
pub const RequestAdapterResponseTag = enum {
adapter,
err,
};
pub const RequestAdapterResponse = union(RequestAdapterResponseTag) {
adapter: Adapter,
err: RequestAdapterError,
};
pub fn requestAdapter(
interface: Interface,
options: *const RequestAdapterOptions,
callback: *RequestAdapterCallback,
) void {
interface.vtable.requestAdapter(interface.ptr, options, callback);
}
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(if (Context == void) {} else @ptrCast(Context, @alignCast(std.meta.alignment(Context), type_erased_ctx)), response);
}
}).erased;
return .{
.type_erased_ctx = if (Context == void) undefined else 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 {
var response: RequestAdapterResponse = undefined;
var callback = RequestAdapterCallback.init(*RequestAdapterResponse, &response, (struct {
pub fn callback(ctx: *RequestAdapterResponse, 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 {
_ = VTable;
_ = reference;
_ = release;
_ = RequestAdapterOptions;
_ = RequestAdapterErrorCode;
_ = RequestAdapterError;
_ = RequestAdapterResponse;
_ = requestAdapter;
_ = waitForAdapter;
}