diff --git a/gpu/src/Adapter.zig b/gpu/src/Adapter.zig index f0449792..6288675f 100644 --- a/gpu/src/Adapter.zig +++ b/gpu/src/Adapter.zig @@ -17,9 +17,11 @@ //! //! https://gpuweb.github.io/gpuweb/#adapters //! https://gpuweb.github.io/gpuweb/#gpuadapter +const std = @import("std"); const FeatureName = @import("feature_name.zig").FeatureName; const SupportedLimits = @import("supported_limits.zig").SupportedLimits; +const Device = @import("Device.zig"); const Adapter = @This(); @@ -43,16 +45,20 @@ fallback: bool, // TODO: docs properties: Properties, -// The type erased pointer to the Adapter implementation +/// The type erased pointer to the Adapter implementation +/// Equal to c.WGPUAdapter for NativeInstance. ptr: *anyopaque, vtable: *const VTable, +// The @frameSize(func) of the implementations requestDevice async function +request_device_frame_size: usize, + pub const VTable = struct { // TODO: - // WGPU_EXPORT void wgpuAdapterRequestDevice(WGPUAdapter adapter, WGPUDeviceDescriptor const * descriptor, WGPURequestDeviceCallback callback, void * userdata); // WGPU_EXPORT WGPUDevice wgpuAdapterCreateDevice(WGPUAdapter adapter, WGPUDeviceDescriptor const * descriptor); reference: fn (ptr: *anyopaque) void, release: fn (ptr: *anyopaque) void, + requestDevice: fn requestDevice(ptr: *anyopaque, descriptor: *const Device.Descriptor) callconv(.Async) RequestDeviceResponse, }; pub inline fn reference(adapter: Adapter) void { @@ -123,10 +129,57 @@ pub fn backendTypeName(t: BackendType) []const u8 { }; } +pub const RequestDeviceErrorCode = error{ + Error, + Unknown, +}; + +// TODO: docs +pub const RequestDeviceError = struct { + message: []const u8, + code: RequestDeviceErrorCode, +}; + +pub const RequestDeviceResponseTag = enum { + device, + err, +}; + +pub const RequestDeviceResponse = union(RequestDeviceResponseTag) { + // TODO: docs + device: Device, + err: RequestDeviceError, +}; + +// TODO: docs +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); + + var result: RequestDeviceResponse = undefined; + const f = @asyncCall(frame_buffer, &result, adapter.vtable.requestDevice, .{ adapter.ptr, descriptor }); + resume f; + return result; +} + test "syntax" { _ = VTable; _ = hasFeature; _ = Properties; _ = Type; _ = BackendType; + _ = RequestDeviceErrorCode; + _ = RequestDeviceError; + _ = RequestDeviceResponse; + _ = requestDevice; } diff --git a/gpu/src/NativeInstance.zig b/gpu/src/NativeInstance.zig index 2e912e3d..52913efa 100644 --- a/gpu/src/NativeInstance.zig +++ b/gpu/src/NativeInstance.zig @@ -9,6 +9,12 @@ 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.RequestDeviceError; +pub const RequestDeviceResponse = Adapter.RequestDeviceResponse; + +pub const Device = @import("Device.zig"); + const Surface = @import("Surface.zig"); const NativeInstance = @This(); @@ -16,6 +22,7 @@ const NativeInstance = @This(); /// The WGPUInstance that is wrapped by this native instance. instance: c.WGPUInstance, +// TODO: use CallbackResponse approach instead of storing here request_adapter_response: ?Interface.RequestAdapterResponse = null, /// Wraps a native WGPUInstance to provide an implementation of the gpu.Interface. @@ -207,6 +214,7 @@ fn wrapAdapter(adapter: c.WGPUAdapter) Adapter { .ptr = adapter.?, .vtable = &adapter_vtable, + .request_device_frame_size = @frameSize(adapter_vtable.requestDevice), }; } @@ -221,9 +229,71 @@ const adapter_vtable = Adapter.VTable{ c.wgpuAdapterRelease(@ptrCast(c.WGPUAdapter, ptr)); } }).release, + .requestDevice = (struct { + pub fn requestDevice(ptr: *anyopaque, descriptor: *const Device.Descriptor) callconv(.Async) RequestDeviceResponse { + const adapter = @ptrCast(c.WGPUAdapter, @alignCast(@alignOf(c.WGPUAdapter), ptr)); + + const desc = c.WGPUDeviceDescriptor{ + .nextInChain = null, + .label = if (descriptor.label) |l| @ptrCast([*c]const u8, l) else null, + .requiredFeaturesCount = if (descriptor.required_features) |f| @intCast(u32, f.len) else 0, + .requiredFeatures = if (descriptor.required_features) |f| @ptrCast([*c]const c_uint, &f[0]) else null, + .requiredLimits = null, // TODO + }; + + 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)); + + // Store the response into a field on the native instance for later reading. + _callback_response.* = if (status == c.WGPURequestDeviceStatus_Success) .{ + .device = wrapDevice(device.?), + } else .{ + .err = Adapter.RequestDeviceError{ + .message = std.mem.span(message), + .code = switch (status) { + c.WGPURequestDeviceStatus_Error => RequestDeviceErrorCode.Error, + c.WGPURequestDeviceStatus_Unknown => RequestDeviceErrorCode.Unknown, + else => unreachable, + }, + }, + }; + } + }).callback; + + 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; + } + }).requestDevice, }; -// TODO: implement Device interface +fn wrapDevice(device: c.WGPUDevice) Device { + // TODO: implement Device interface + return .{ + .ptr = device.?, + .vtable = &device_vtable, + }; +} + +const device_vtable = Device.VTable{ + .reference = (struct { + pub fn reference(ptr: *anyopaque) void { + c.wgpuDeviceReference(@ptrCast(c.WGPUDevice, ptr)); + } + }).reference, + .release = (struct { + pub fn release(ptr: *anyopaque) void { + c.wgpuDeviceRelease(@ptrCast(c.WGPUDevice, ptr)); + } + }).release, +}; test "syntax" { _ = wrap; @@ -232,4 +302,6 @@ test "syntax" { _ = createSurface; _ = surface_vtable; _ = adapter_vtable; + _ = wrapDevice; + _ = device_vtable; } diff --git a/gpu/src/TODO b/gpu/src/TODO index bf065385..3e07136e 100644 --- a/gpu/src/TODO +++ b/gpu/src/TODO @@ -269,13 +269,6 @@ typedef enum WGPURenderPassTimestampLocation { WGPURenderPassTimestampLocation_Force32 = 0x7FFFFFFF } WGPURenderPassTimestampLocation; -typedef enum WGPURequestDeviceStatus { - WGPURequestDeviceStatus_Success = 0x00000000, - WGPURequestDeviceStatus_Error = 0x00000001, - WGPURequestDeviceStatus_Unknown = 0x00000002, - WGPURequestDeviceStatus_Force32 = 0x7FFFFFFF -} WGPURequestDeviceStatus; - typedef enum WGPUSType { WGPUSType_Invalid = 0x00000000, WGPUSType_ShaderModuleSPIRVDescriptor = 0x00000005, @@ -1006,14 +999,6 @@ typedef struct WGPUComputePipelineDescriptor { WGPUProgrammableStageDescriptor compute; } WGPUComputePipelineDescriptor; -typedef struct WGPUDeviceDescriptor { - WGPUChainedStruct const * nextInChain; - char const * label; - uint32_t requiredFeaturesCount; - WGPUFeatureName const * requiredFeatures; - WGPURequiredLimits const * requiredLimits; -} WGPUDeviceDescriptor; - typedef struct WGPUDeviceProperties { uint32_t deviceID; uint32_t vendorID; @@ -1085,7 +1070,6 @@ typedef void (*WGPUErrorCallback)(WGPUErrorType type, char const * message, void typedef void (*WGPULoggingCallback)(WGPULoggingType type, char const * message, void * userdata); typedef void (*WGPUProc)(); typedef void (*WGPUQueueWorkDoneCallback)(WGPUQueueWorkDoneStatus status, void * userdata); -typedef void (*WGPURequestDeviceCallback)(WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * userdata); WGPU_EXPORT WGPUProc wgpuGetProcAddress(WGPUDevice device, char const * procName);