2287 lines
92 KiB
Zig
2287 lines
92 KiB
Zig
//! A native webgpu.h implementation of the gpu.Interface
|
|
const std = @import("std");
|
|
const c = @import("c.zig").c;
|
|
|
|
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 RequestDeviceCallback = Adapter.RequestDeviceCallback;
|
|
const RequestDeviceResponse = Adapter.RequestDeviceResponse;
|
|
|
|
const Limits = @import("data.zig").Limits;
|
|
const Color = @import("data.zig").Color;
|
|
const Extent3D = @import("data.zig").Extent3D;
|
|
|
|
const Device = @import("Device.zig");
|
|
const Surface = @import("Surface.zig");
|
|
const Queue = @import("Queue.zig");
|
|
const CommandBuffer = @import("CommandBuffer.zig");
|
|
const ShaderModule = @import("ShaderModule.zig");
|
|
const SwapChain = @import("SwapChain.zig");
|
|
const TextureView = @import("TextureView.zig");
|
|
const Texture = @import("Texture.zig");
|
|
const Sampler = @import("Sampler.zig");
|
|
const RenderPipeline = @import("RenderPipeline.zig");
|
|
const RenderPassEncoder = @import("RenderPassEncoder.zig");
|
|
const RenderBundleEncoder = @import("RenderBundleEncoder.zig");
|
|
const RenderBundle = @import("RenderBundle.zig");
|
|
const QuerySet = @import("QuerySet.zig");
|
|
const PipelineLayout = @import("PipelineLayout.zig");
|
|
const ExternalTexture = @import("ExternalTexture.zig");
|
|
const BindGroup = @import("BindGroup.zig");
|
|
const BindGroupLayout = @import("BindGroupLayout.zig");
|
|
const Buffer = @import("Buffer.zig");
|
|
const CommandEncoder = @import("CommandEncoder.zig");
|
|
const ComputePassEncoder = @import("ComputePassEncoder.zig");
|
|
const ComputePipeline = @import("ComputePipeline.zig");
|
|
|
|
const PresentMode = @import("enums.zig").PresentMode;
|
|
const IndexFormat = @import("enums.zig").IndexFormat;
|
|
const ErrorType = @import("enums.zig").ErrorType;
|
|
const ErrorFilter = @import("enums.zig").ErrorFilter;
|
|
const LoggingType = @import("enums.zig").LoggingType;
|
|
const Feature = @import("enums.zig").Feature;
|
|
|
|
const ImageCopyBuffer = @import("structs.zig").ImageCopyBuffer;
|
|
const ImageCopyTexture = @import("structs.zig").ImageCopyTexture;
|
|
const ErrorCallback = @import("structs.zig").ErrorCallback;
|
|
const LoggingCallback = @import("structs.zig").LoggingCallback;
|
|
|
|
const NativeInstance = @This();
|
|
|
|
/// The WGPUInstance that is wrapped by this native instance.
|
|
instance: c.WGPUInstance,
|
|
|
|
/// Wraps a native WGPUInstance to provide an implementation of the gpu.Interface.
|
|
pub fn wrap(instance: *anyopaque) NativeInstance {
|
|
return .{ .instance = @ptrCast(c.WGPUInstance, instance) };
|
|
}
|
|
|
|
const interface_vtable = Interface.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
const native = @ptrCast(*NativeInstance, @alignCast(std.meta.alignment(*NativeInstance), ptr));
|
|
c.wgpuInstanceReference(native.instance);
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
const native = @ptrCast(*NativeInstance, @alignCast(std.meta.alignment(*NativeInstance), ptr));
|
|
c.wgpuInstanceRelease(native.instance);
|
|
}
|
|
}).release,
|
|
.requestAdapter = (struct {
|
|
pub fn requestAdapter(
|
|
ptr: *anyopaque,
|
|
options: *const RequestAdapterOptions,
|
|
callback: *RequestAdapterCallback,
|
|
) void {
|
|
const native = @ptrCast(*NativeInstance, @alignCast(std.meta.alignment(*NativeInstance), ptr));
|
|
|
|
const opt = c.WGPURequestAdapterOptions{
|
|
.nextInChain = null,
|
|
.compatibleSurface = if (options.compatible_surface) |surface| @ptrCast(c.WGPUSurface, surface.ptr) else null,
|
|
.powerPreference = @enumToInt(options.power_preference),
|
|
.forceFallbackAdapter = options.force_fallback_adapter,
|
|
};
|
|
|
|
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(std.meta.alignment(*RequestAdapterCallback), userdata.?));
|
|
|
|
// Store the response into a field on the native instance for later reading.
|
|
const response = if (status == c.WGPURequestAdapterStatus_Success) RequestAdapterResponse{
|
|
.adapter = wrapAdapter(adapter.?),
|
|
} else RequestAdapterResponse{
|
|
.err = Interface.RequestAdapterError{
|
|
.message = std.mem.span(message),
|
|
.code = switch (status) {
|
|
c.WGPURequestAdapterStatus_Unavailable => RequestAdapterErrorCode.Unavailable,
|
|
c.WGPURequestAdapterStatus_Error => RequestAdapterErrorCode.Error,
|
|
c.WGPURequestAdapterStatus_Unknown => RequestAdapterErrorCode.Unknown,
|
|
else => unreachable,
|
|
},
|
|
},
|
|
};
|
|
|
|
callback_info.type_erased_callback(callback_info.type_erased_ctx, response);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuInstanceRequestAdapter(native.instance, &opt, cCallback, callback);
|
|
}
|
|
}).requestAdapter,
|
|
};
|
|
|
|
/// Returns the gpu.Interface for interacting with this native instance.
|
|
pub fn interface(native: *NativeInstance) Interface {
|
|
return .{
|
|
.ptr = native,
|
|
.vtable = &interface_vtable,
|
|
};
|
|
}
|
|
|
|
pub fn createSurface(native: *const NativeInstance, descriptor: *const Surface.Descriptor) Surface {
|
|
const surface = switch (descriptor.*) {
|
|
.metal_layer => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromMetalLayer = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromMetalLayer;
|
|
desc.layer = src.layer;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
.windows_hwnd => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromWindowsHWND = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromWindowsHWND;
|
|
desc.hinstance = src.hinstance;
|
|
desc.hwnd = src.hwnd;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
.windows_core_window => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromWindowsCoreWindow = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromWindowsCoreWindow;
|
|
desc.coreWindow = src.core_window;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
.windows_swap_chain_panel => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromWindowsSwapChainPanel = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromWindowsSwapChainPanel;
|
|
desc.swapChainPanel = src.swap_chain_panel;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
.xlib => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromXlibWindow = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromXlibWindow;
|
|
desc.display = src.display;
|
|
desc.window = src.window;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
.canvas_html_selector => |src| blk: {
|
|
var desc: c.WGPUSurfaceDescriptorFromCanvasHTMLSelector = undefined;
|
|
desc.chain.next = null;
|
|
desc.chain.sType = c.WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
|
desc.selector = src.selector;
|
|
break :blk c.wgpuInstanceCreateSurface(native.instance, &c.WGPUSurfaceDescriptor{
|
|
.nextInChain = @ptrCast(*c.WGPUChainedStruct, &desc),
|
|
.label = if (src.label) |l| l else null,
|
|
});
|
|
},
|
|
};
|
|
|
|
return Surface{
|
|
.ptr = surface.?,
|
|
.vtable = &surface_vtable,
|
|
};
|
|
}
|
|
|
|
const surface_vtable = Surface.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuSurfaceReference(@ptrCast(c.WGPUSurface, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuSurfaceRelease(@ptrCast(c.WGPUSurface, ptr));
|
|
}
|
|
}).release,
|
|
};
|
|
|
|
pub inline fn fromWGPUAdapter(adapter: *anyopaque) Adapter {
|
|
return wrapAdapter(@ptrCast(c.WGPUAdapter, adapter));
|
|
}
|
|
|
|
pub fn wrapAdapter(adapter: c.WGPUAdapter) Adapter {
|
|
var c_props: c.WGPUAdapterProperties = undefined;
|
|
c.wgpuAdapterGetProperties(adapter, &c_props);
|
|
const properties = Adapter.Properties{
|
|
.vendor_id = c_props.vendorID,
|
|
.device_id = c_props.deviceID,
|
|
.name = std.mem.span(c_props.name),
|
|
.driver_description = std.mem.span(c_props.driverDescription),
|
|
.adapter_type = @intToEnum(Adapter.Type, c_props.adapterType),
|
|
.backend_type = @intToEnum(Adapter.BackendType, c_props.backendType),
|
|
};
|
|
|
|
var supported_limits: c.WGPUSupportedLimits = undefined;
|
|
supported_limits.nextInChain = null;
|
|
if (!c.wgpuAdapterGetLimits(adapter.?, &supported_limits)) @panic("failed to get adapter limits (this is a bug in mach/gpu)");
|
|
|
|
var wrapped = Adapter{
|
|
.features = undefined,
|
|
.limits = @bitCast(Limits, supported_limits.limits),
|
|
.properties = properties,
|
|
|
|
// TODO: why is fallback not queryable on Dawn?
|
|
.fallback = false,
|
|
|
|
.ptr = adapter.?,
|
|
.vtable = &adapter_vtable,
|
|
};
|
|
|
|
const features_len = c.wgpuAdapterEnumerateFeatures(adapter.?, @ptrCast([*]c.WGPUFeatureName, &wrapped._features));
|
|
wrapped.features = wrapped._features[0..features_len];
|
|
return wrapped;
|
|
}
|
|
|
|
const adapter_vtable = Adapter.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuAdapterReference(@ptrCast(c.WGPUAdapter, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuAdapterRelease(@ptrCast(c.WGPUAdapter, ptr));
|
|
}
|
|
}).release,
|
|
.requestDevice = (struct {
|
|
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{
|
|
.nextInChain = null,
|
|
.limits = @bitCast(c.WGPULimits, l),
|
|
} else null;
|
|
|
|
const desc = c.WGPUDeviceDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.requiredFeaturesCount = if (descriptor.required_features) |f| @intCast(u32, f.len) else 0,
|
|
.requiredFeatures = if (descriptor.required_features) |f| @ptrCast([*]const c_uint, f.ptr) else null,
|
|
.requiredLimits = if (required_limits) |*l| l else null,
|
|
.defaultQueue = if (descriptor.default_queue) |q| .{ .nextInChain = null, .label = q.label } else .{ .nextInChain = null, .label = null },
|
|
};
|
|
|
|
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(std.meta.alignment(*RequestDeviceCallback), userdata.?));
|
|
|
|
const response = if (status == c.WGPURequestDeviceStatus_Success) RequestDeviceResponse{
|
|
.device = wrapDevice(device.?),
|
|
} else RequestDeviceResponse{
|
|
.err = Adapter.RequestDeviceError{
|
|
.message = std.mem.span(message),
|
|
.code = switch (status) {
|
|
c.WGPURequestDeviceStatus_Error => RequestDeviceErrorCode.Error,
|
|
c.WGPURequestDeviceStatus_Unknown => RequestDeviceErrorCode.Unknown,
|
|
else => unreachable,
|
|
},
|
|
},
|
|
};
|
|
|
|
callback_info.type_erased_callback(callback_info.type_erased_ctx, response);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuAdapterRequestDevice(adapter, &desc, cCallback, callback);
|
|
}
|
|
}).requestDevice,
|
|
};
|
|
|
|
fn wrapDevice(device: c.WGPUDevice) Device {
|
|
var supported_limits: c.WGPUSupportedLimits = undefined;
|
|
supported_limits.nextInChain = null;
|
|
if (!c.wgpuDeviceGetLimits(device.?, &supported_limits)) @panic("failed to get device limits (this is a bug in mach/gpu)");
|
|
|
|
var wrapped = Device{
|
|
.features = undefined,
|
|
.limits = @bitCast(Limits, supported_limits.limits),
|
|
.ptr = device.?,
|
|
.vtable = &device_vtable,
|
|
};
|
|
|
|
const features_len = c.wgpuDeviceEnumerateFeatures(device.?, @ptrCast([*]c.WGPUFeatureName, &wrapped._features));
|
|
wrapped.features = wrapped._features[0..features_len];
|
|
return wrapped;
|
|
}
|
|
|
|
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,
|
|
.getQueue = (struct {
|
|
pub fn getQueue(ptr: *anyopaque) Queue {
|
|
return wrapQueue(c.wgpuDeviceGetQueue(@ptrCast(c.WGPUDevice, ptr)));
|
|
}
|
|
}).getQueue,
|
|
.injectError = (struct {
|
|
pub fn injectError(ptr: *anyopaque, typ: ErrorType, message: [*:0]const u8) void {
|
|
c.wgpuDeviceInjectError(@ptrCast(c.WGPUDevice, ptr), @enumToInt(typ), message);
|
|
}
|
|
}).injectError,
|
|
.loseForTesting = (struct {
|
|
pub fn loseForTesting(ptr: *anyopaque) void {
|
|
c.wgpuDeviceLoseForTesting(@ptrCast(c.WGPUDevice, ptr));
|
|
}
|
|
}).loseForTesting,
|
|
.popErrorScope = (struct {
|
|
pub fn popErrorScope(ptr: *anyopaque, callback: *ErrorCallback) bool {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
typ: c.WGPUErrorType,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*ErrorCallback, @alignCast(std.meta.alignment(*ErrorCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(ErrorType, typ),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
return c.wgpuDevicePopErrorScope(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).popErrorScope,
|
|
.createBindGroup = (struct {
|
|
pub fn createBindGroup(ptr: *anyopaque, descriptor: *const BindGroup.Descriptor) BindGroup {
|
|
var few_entries: [16]c.WGPUBindGroupEntry = undefined;
|
|
const entries = if (descriptor.entries.len <= 8)
|
|
few_entries[0..descriptor.entries.len]
|
|
else
|
|
std.heap.page_allocator.alloc(c.WGPUBindGroupEntry, descriptor.entries.len) catch unreachable;
|
|
defer if (entries.len > 8) std.heap.page_allocator.free(entries);
|
|
|
|
for (descriptor.entries) |entry, i| {
|
|
entries[i] = c.WGPUBindGroupEntry{
|
|
.nextInChain = null,
|
|
.binding = entry.binding,
|
|
.buffer = if (entry.buffer) |buf|
|
|
@ptrCast(c.WGPUBuffer, buf.ptr)
|
|
else
|
|
null,
|
|
.offset = entry.offset,
|
|
.size = entry.size,
|
|
.sampler = if (entry.sampler) |samp|
|
|
@ptrCast(c.WGPUSampler, samp.ptr)
|
|
else
|
|
null,
|
|
.textureView = if (entry.texture_view) |tex|
|
|
@ptrCast(c.WGPUTextureView, tex.ptr)
|
|
else
|
|
null,
|
|
};
|
|
}
|
|
|
|
const desc = c.WGPUBindGroupDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.layout = @ptrCast(c.WGPUBindGroupLayout, descriptor.layout.ptr),
|
|
.entryCount = @intCast(u32, entries.len),
|
|
.entries = entries.ptr,
|
|
};
|
|
|
|
return wrapBindGroup(c.wgpuDeviceCreateBindGroup(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createBindGroup,
|
|
.pushErrorScope = (struct {
|
|
pub fn pushErrorScope(ptr: *anyopaque, filter: ErrorFilter) void {
|
|
c.wgpuDevicePushErrorScope(@ptrCast(c.WGPUDevice, ptr), @enumToInt(filter));
|
|
}
|
|
}).pushErrorScope,
|
|
.setLostCallback = (struct {
|
|
pub fn setLostCallback(ptr: *anyopaque, callback: *Device.LostCallback) void {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
reason: c.WGPUDeviceLostReason,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*Device.LostCallback, @alignCast(std.meta.alignment(*Device.LostCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(Device.LostReason, reason),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuDeviceSetDeviceLostCallback(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).setLostCallback,
|
|
.createBindGroupLayout = (struct {
|
|
pub fn createBindGroupLayout(ptr: *anyopaque, descriptor: *const BindGroupLayout.Descriptor) BindGroupLayout {
|
|
const desc = c.WGPUBindGroupLayoutDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.entryCount = @intCast(u32, descriptor.entries.len),
|
|
.entries = @ptrCast([*]const c.WGPUBindGroupLayoutEntry, descriptor.entries.ptr),
|
|
};
|
|
return wrapBindGroupLayout(c.wgpuDeviceCreateBindGroupLayout(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createBindGroupLayout,
|
|
.createSampler = (struct {
|
|
pub fn createSampler(ptr: *anyopaque, descriptor: *const Sampler.Descriptor) Sampler {
|
|
return wrapSampler(c.wgpuDeviceCreateSampler(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
@ptrCast(*const c.WGPUSamplerDescriptor, descriptor),
|
|
));
|
|
}
|
|
}).createSampler,
|
|
.createShaderModule = (struct {
|
|
pub fn createShaderModule(ptr: *anyopaque, descriptor: *const ShaderModule.Descriptor) ShaderModule {
|
|
switch (descriptor.code) {
|
|
.wgsl => |wgsl| {
|
|
const wgsl_desc = c.WGPUShaderModuleWGSLDescriptor{
|
|
.chain = c.WGPUChainedStruct{
|
|
.next = null,
|
|
.sType = c.WGPUSType_ShaderModuleWGSLDescriptor,
|
|
},
|
|
.source = wgsl,
|
|
};
|
|
const desc = c.WGPUShaderModuleDescriptor{
|
|
.nextInChain = @ptrCast(*const c.WGPUChainedStruct, &wgsl_desc),
|
|
.label = if (descriptor.label) |l| l else null,
|
|
};
|
|
return wrapShaderModule(c.wgpuDeviceCreateShaderModule(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
},
|
|
.spirv => |spirv| {
|
|
const spirv_desc = c.WGPUShaderModuleSPIRVDescriptor{
|
|
.chain = c.WGPUChainedStruct{
|
|
.next = null,
|
|
.sType = c.WGPUSType_ShaderModuleSPIRVDescriptor,
|
|
},
|
|
.code = spirv.ptr,
|
|
.codeSize = @intCast(u32, spirv.len),
|
|
};
|
|
const desc = c.WGPUShaderModuleDescriptor{
|
|
.nextInChain = @ptrCast(*const c.WGPUChainedStruct, &spirv_desc),
|
|
.label = if (descriptor.label) |l| l else null,
|
|
};
|
|
return wrapShaderModule(c.wgpuDeviceCreateShaderModule(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
},
|
|
}
|
|
}
|
|
}).createShaderModule,
|
|
.nativeCreateSwapChain = (struct {
|
|
pub fn nativeCreateSwapChain(ptr: *anyopaque, surface: ?Surface, descriptor: *const SwapChain.Descriptor) SwapChain {
|
|
const desc = c.WGPUSwapChainDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.usage = @bitCast(u32, descriptor.usage),
|
|
.format = @enumToInt(descriptor.format),
|
|
.width = descriptor.width,
|
|
.height = descriptor.height,
|
|
.presentMode = @enumToInt(descriptor.present_mode),
|
|
.implementation = descriptor.implementation,
|
|
};
|
|
return wrapSwapChain(c.wgpuDeviceCreateSwapChain(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
if (surface) |surf| @ptrCast(c.WGPUSurface, surf.ptr) else null,
|
|
&desc,
|
|
));
|
|
}
|
|
}).nativeCreateSwapChain,
|
|
.createTexture = (struct {
|
|
pub fn createTexture(ptr: *anyopaque, descriptor: *const Texture.Descriptor) Texture {
|
|
const desc = c.WGPUTextureDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.usage = @bitCast(u32, descriptor.usage),
|
|
.dimension = @enumToInt(descriptor.dimension),
|
|
.size = @bitCast(c.WGPUExtent3D, descriptor.size),
|
|
.format = @enumToInt(descriptor.format),
|
|
.mipLevelCount = descriptor.mip_level_count,
|
|
.sampleCount = descriptor.sample_count,
|
|
.viewFormatCount = if (descriptor.view_formats) |vf| @intCast(u32, vf.len) else 0,
|
|
.viewFormats = if (descriptor.view_formats) |vf| @ptrCast([*]const c.WGPUTextureFormat, vf.ptr) else null,
|
|
};
|
|
return wrapTexture(c.wgpuDeviceCreateTexture(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createTexture,
|
|
.destroy = (struct {
|
|
pub fn destroy(ptr: *anyopaque) void {
|
|
c.wgpuDeviceDestroy(@ptrCast(c.WGPUDevice, ptr));
|
|
}
|
|
}).destroy,
|
|
.createBuffer = (struct {
|
|
pub fn createBuffer(ptr: *anyopaque, descriptor: *const Buffer.Descriptor) Buffer {
|
|
return wrapBuffer(c.wgpuDeviceCreateBuffer(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
@ptrCast(*const c.WGPUBufferDescriptor, descriptor),
|
|
));
|
|
}
|
|
}).createBuffer,
|
|
.createCommandEncoder = (struct {
|
|
pub fn createCommandEncoder(ptr: *anyopaque, descriptor: ?*const CommandEncoder.Descriptor) CommandEncoder {
|
|
const desc: ?*c.WGPUCommandEncoderDescriptor = if (descriptor) |d| &.{
|
|
.nextInChain = null,
|
|
.label = if (d.label) |l| l else "",
|
|
} else null;
|
|
return wrapCommandEncoder(c.wgpuDeviceCreateCommandEncoder(@ptrCast(c.WGPUDevice, ptr), desc));
|
|
}
|
|
}).createCommandEncoder,
|
|
.createComputePipeline = (struct {
|
|
pub fn createComputePipeline(
|
|
ptr: *anyopaque,
|
|
descriptor: *const ComputePipeline.Descriptor,
|
|
) ComputePipeline {
|
|
const desc = convertComputePipelineDescriptor(descriptor);
|
|
|
|
return wrapComputePipeline(c.wgpuDeviceCreateComputePipeline(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
&desc,
|
|
));
|
|
}
|
|
}).createComputePipeline,
|
|
.createComputePipelineAsync = (struct {
|
|
pub fn createComputePipelineAsync(
|
|
ptr: *anyopaque,
|
|
descriptor: *const ComputePipeline.Descriptor,
|
|
callback: *ComputePipeline.CreateCallback,
|
|
) void {
|
|
const desc = convertComputePipelineDescriptor(descriptor);
|
|
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
status: c.WGPUCreatePipelineAsyncStatus,
|
|
pipeline: c.WGPUComputePipeline,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*ComputePipeline.CreateCallback, @alignCast(std.meta.alignment(*ComputePipeline.CreateCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(ComputePipeline.CreateStatus, status),
|
|
wrapComputePipeline(pipeline),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuDeviceCreateComputePipelineAsync(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
&desc,
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).createComputePipelineAsync,
|
|
.createErrorBuffer = (struct {
|
|
pub fn createErrorBuffer(ptr: *anyopaque) Buffer {
|
|
return wrapBuffer(c.wgpuDeviceCreateErrorBuffer(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
));
|
|
}
|
|
}).createErrorBuffer,
|
|
.createExternalTexture = (struct {
|
|
pub fn createExternalTexture(ptr: *anyopaque, descriptor: *const ExternalTexture.Descriptor) ExternalTexture {
|
|
const desc = c.WGPUExternalTextureDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.plane0 = @ptrCast(c.WGPUTextureView, descriptor.plane0.ptr),
|
|
.plane1 = @ptrCast(c.WGPUTextureView, descriptor.plane1.ptr),
|
|
.colorSpace = @enumToInt(descriptor.color_space),
|
|
};
|
|
return wrapExternalTexture(c.wgpuDeviceCreateExternalTexture(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createExternalTexture,
|
|
.createPipelineLayout = (struct {
|
|
pub fn createPipelineLayout(ptr: *anyopaque, descriptor: *const PipelineLayout.Descriptor) PipelineLayout {
|
|
var few_bind_group_layouts: [16]c.WGPUBindGroupLayout = undefined;
|
|
const bind_group_layouts = if (descriptor.bind_group_layouts.len <= 16) blk: {
|
|
for (descriptor.bind_group_layouts) |layout, i| {
|
|
few_bind_group_layouts[i] = @ptrCast(c.WGPUBindGroupLayout, layout.ptr);
|
|
}
|
|
break :blk few_bind_group_layouts[0..descriptor.bind_group_layouts.len];
|
|
} else blk: {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPUBindGroupLayout, descriptor.bind_group_layouts.len) catch unreachable;
|
|
for (descriptor.bind_group_layouts) |layout, i| {
|
|
mem[i] = @ptrCast(c.WGPUBindGroupLayout, layout.ptr);
|
|
}
|
|
break :blk mem;
|
|
};
|
|
defer if (descriptor.bind_group_layouts.len > 16) std.heap.page_allocator.free(descriptor.bind_group_layouts);
|
|
|
|
const desc = c.WGPUPipelineLayoutDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.bindGroupLayoutCount = @intCast(u32, bind_group_layouts.len),
|
|
.bindGroupLayouts = bind_group_layouts.ptr,
|
|
};
|
|
return wrapPipelineLayout(c.wgpuDeviceCreatePipelineLayout(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createPipelineLayout,
|
|
.createQuerySet = (struct {
|
|
pub fn createQuerySet(ptr: *anyopaque, descriptor: *const QuerySet.Descriptor) QuerySet {
|
|
const desc = c.WGPUQuerySetDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.type = @enumToInt(descriptor.type),
|
|
.count = descriptor.count,
|
|
.pipelineStatistics = @ptrCast([*]const c.WGPUPipelineStatisticName, descriptor.pipeline_statistics.ptr),
|
|
.pipelineStatisticsCount = @intCast(u32, descriptor.pipeline_statistics.len),
|
|
};
|
|
return wrapQuerySet(c.wgpuDeviceCreateQuerySet(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createQuerySet,
|
|
.createRenderBundleEncoder = (struct {
|
|
pub fn createRenderBundleEncoder(ptr: *anyopaque, descriptor: *const RenderBundleEncoder.Descriptor) RenderBundleEncoder {
|
|
const desc = c.WGPURenderBundleEncoderDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.colorFormatsCount = @intCast(u32, descriptor.color_formats.len),
|
|
.colorFormats = @ptrCast([*]const c.WGPUTextureFormat, descriptor.color_formats.ptr),
|
|
.depthStencilFormat = @enumToInt(descriptor.depth_stencil_format),
|
|
.sampleCount = descriptor.sample_count,
|
|
.depthReadOnly = descriptor.depth_read_only,
|
|
.stencilReadOnly = descriptor.stencil_read_only,
|
|
};
|
|
return wrapRenderBundleEncoder(c.wgpuDeviceCreateRenderBundleEncoder(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createRenderBundleEncoder,
|
|
.createRenderPipeline = (struct {
|
|
pub fn createRenderPipeline(ptr: *anyopaque, descriptor: *const RenderPipeline.Descriptor) RenderPipeline {
|
|
var tmp_depth_stencil: c.WGPUDepthStencilState = undefined;
|
|
var tmp_fragment_state: c.WGPUFragmentState = undefined;
|
|
const desc = convertRenderPipelineDescriptor(descriptor, &tmp_depth_stencil, &tmp_fragment_state);
|
|
return wrapRenderPipeline(c.wgpuDeviceCreateRenderPipeline(@ptrCast(c.WGPUDevice, ptr), &desc));
|
|
}
|
|
}).createRenderPipeline,
|
|
.createRenderPipelineAsync = (struct {
|
|
pub fn createRenderPipelineAsync(
|
|
ptr: *anyopaque,
|
|
descriptor: *const RenderPipeline.Descriptor,
|
|
callback: *RenderPipeline.CreateCallback,
|
|
) void {
|
|
var tmp_depth_stencil: c.WGPUDepthStencilState = undefined;
|
|
var tmp_fragment_state: c.WGPUFragmentState = undefined;
|
|
const desc = convertRenderPipelineDescriptor(descriptor, &tmp_depth_stencil, &tmp_fragment_state);
|
|
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
status: c.WGPUCreatePipelineAsyncStatus,
|
|
pipeline: c.WGPURenderPipeline,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*RenderPipeline.CreateCallback, @alignCast(std.meta.alignment(*RenderPipeline.CreateCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(RenderPipeline.CreateStatus, status),
|
|
wrapRenderPipeline(pipeline),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuDeviceCreateRenderPipelineAsync(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
&desc,
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).createRenderPipelineAsync,
|
|
.setUncapturedErrorCallback = (struct {
|
|
pub fn setUncapturedErrorCallback(
|
|
ptr: *anyopaque,
|
|
callback: *ErrorCallback,
|
|
) void {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
typ: c.WGPUErrorType,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*ErrorCallback, @alignCast(std.meta.alignment(*ErrorCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(ErrorType, typ),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
return c.wgpuDeviceSetUncapturedErrorCallback(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).setUncapturedErrorCallback,
|
|
.setLoggingCallback = (struct {
|
|
pub fn setLoggingCallback(
|
|
ptr: *anyopaque,
|
|
callback: *LoggingCallback,
|
|
) void {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(
|
|
typ: c.WGPULoggingType,
|
|
message: [*c]const u8,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) void {
|
|
const callback_info = @ptrCast(*LoggingCallback, @alignCast(std.meta.alignment(*LoggingCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(LoggingType, typ),
|
|
std.mem.span(message),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
return c.wgpuDeviceSetLoggingCallback(
|
|
@ptrCast(c.WGPUDevice, ptr),
|
|
cCallback,
|
|
callback,
|
|
);
|
|
}
|
|
}).setLoggingCallback,
|
|
.tick = (struct {
|
|
pub fn tick(ptr: *anyopaque) void {
|
|
c.wgpuDeviceTick(@ptrCast(c.WGPUDevice, ptr));
|
|
}
|
|
}.tick),
|
|
};
|
|
|
|
inline fn convertComputePipelineDescriptor(descriptor: *const ComputePipeline.Descriptor) c.WGPUComputePipelineDescriptor {
|
|
return .{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
.layout = if (descriptor.layout) |l| @ptrCast(c.WGPUPipelineLayout, l.ptr) else null,
|
|
.compute = c.WGPUProgrammableStageDescriptor{
|
|
.nextInChain = null,
|
|
.module = @ptrCast(c.WGPUShaderModule, descriptor.compute.module.ptr),
|
|
.entryPoint = descriptor.compute.entry_point,
|
|
.constantCount = if (descriptor.compute.constants) |v| @intCast(u32, v.len) else 0,
|
|
.constants = if (descriptor.compute.constants) |v| @ptrCast([*]const c.WGPUConstantEntry, v.ptr) else null,
|
|
},
|
|
};
|
|
}
|
|
|
|
inline fn convertRenderPipelineDescriptor(
|
|
d: *const RenderPipeline.Descriptor,
|
|
tmp_depth_stencil: *c.WGPUDepthStencilState,
|
|
tmp_fragment_state: *c.WGPUFragmentState,
|
|
) c.WGPURenderPipelineDescriptor {
|
|
if (d.depth_stencil) |ds| {
|
|
tmp_depth_stencil.* = c.WGPUDepthStencilState{
|
|
.nextInChain = null,
|
|
.format = @enumToInt(ds.format),
|
|
.depthWriteEnabled = ds.depth_write_enabled,
|
|
.depthCompare = @enumToInt(ds.depth_compare),
|
|
.stencilFront = @bitCast(c.WGPUStencilFaceState, ds.stencil_front),
|
|
.stencilBack = @bitCast(c.WGPUStencilFaceState, ds.stencil_back),
|
|
.stencilReadMask = ds.stencil_read_mask,
|
|
.stencilWriteMask = ds.stencil_write_mask,
|
|
.depthBias = ds.depth_bias,
|
|
.depthBiasSlopeScale = ds.depth_bias_slope_scale,
|
|
.depthBiasClamp = ds.depth_bias_clamp,
|
|
};
|
|
}
|
|
|
|
if (d.fragment) |frag| {
|
|
tmp_fragment_state.* = c.WGPUFragmentState{
|
|
.nextInChain = null,
|
|
.module = @ptrCast(c.WGPUShaderModule, frag.module.ptr),
|
|
.entryPoint = frag.entry_point,
|
|
.constantCount = if (frag.constants) |v| @intCast(u32, v.len) else 0,
|
|
.constants = if (frag.constants) |v| @ptrCast([*]const c.WGPUConstantEntry, v.ptr) else null,
|
|
.targetCount = if (frag.targets) |v| @intCast(u32, v.len) else 0,
|
|
.targets = if (frag.targets) |v| @ptrCast([*]const c.WGPUColorTargetState, v.ptr) else null,
|
|
};
|
|
}
|
|
|
|
return c.WGPURenderPipelineDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (d.label) |l| l else null,
|
|
.layout = if (d.layout) |v| @ptrCast(c.WGPUPipelineLayout, v.ptr) else null,
|
|
.vertex = c.WGPUVertexState{
|
|
.nextInChain = null,
|
|
.module = @ptrCast(c.WGPUShaderModule, d.vertex.module.ptr),
|
|
.entryPoint = d.vertex.entry_point,
|
|
.constantCount = if (d.vertex.constants) |v| @intCast(u32, v.len) else 0,
|
|
.constants = if (d.vertex.constants) |v| @ptrCast([*]const c.WGPUConstantEntry, v.ptr) else null,
|
|
.bufferCount = if (d.vertex.buffers) |v| @intCast(u32, v.len) else 0,
|
|
.buffers = if (d.vertex.buffers) |v| @ptrCast([*]const c.WGPUVertexBufferLayout, v.ptr) else null,
|
|
},
|
|
.primitive = c.WGPUPrimitiveState{
|
|
.nextInChain = null,
|
|
.topology = @enumToInt(d.primitive.topology),
|
|
.stripIndexFormat = @enumToInt(d.primitive.strip_index_format),
|
|
.frontFace = @enumToInt(d.primitive.front_face),
|
|
.cullMode = @enumToInt(d.primitive.cull_mode),
|
|
},
|
|
.depthStencil = if (d.depth_stencil != null) tmp_depth_stencil else null,
|
|
.multisample = c.WGPUMultisampleState{
|
|
.nextInChain = null,
|
|
.count = d.multisample.count,
|
|
.mask = d.multisample.mask,
|
|
.alphaToCoverageEnabled = d.multisample.alpha_to_coverage_enabled,
|
|
},
|
|
.fragment = if (d.fragment != null) tmp_fragment_state else null,
|
|
};
|
|
}
|
|
|
|
fn wrapQueue(queue: c.WGPUQueue) Queue {
|
|
return .{
|
|
.ptr = queue.?,
|
|
.vtable = &queue_vtable,
|
|
};
|
|
}
|
|
|
|
const queue_vtable = Queue.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuQueueReference(@ptrCast(c.WGPUQueue, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuQueueRelease(@ptrCast(c.WGPUQueue, ptr));
|
|
}
|
|
}).release,
|
|
.submit = (struct {
|
|
pub fn submit(queue: *Queue, cmds: []const CommandBuffer) void {
|
|
const wgpu_queue = @ptrCast(c.WGPUQueue, queue.ptr);
|
|
|
|
if (queue.on_submitted_work_done) |_| {
|
|
// Note: signalValue is not available in the web API, and it's usage is undocumented
|
|
// kainino says "It's basically reserved for future use, though it's been suggested
|
|
// to remove it instead"
|
|
const signal_value: u64 = 0;
|
|
|
|
const cCallback = (struct {
|
|
pub fn cCallback(status: c.WGPUQueueWorkDoneStatus, userdata: ?*anyopaque) callconv(.C) void {
|
|
const callback_info = @ptrCast(*Queue.WorkDoneCallback, @alignCast(std.meta.alignment(*Queue.WorkDoneCallback), userdata));
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(Queue.WorkDoneStatus, status),
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuQueueOnSubmittedWorkDone(
|
|
wgpu_queue,
|
|
signal_value,
|
|
cCallback,
|
|
&queue.on_submitted_work_done,
|
|
);
|
|
}
|
|
|
|
var few_commands: [16]c.WGPUCommandBuffer = undefined;
|
|
const commands = if (cmds.len <= 16) blk: {
|
|
for (cmds) |cmd, i| {
|
|
few_commands[i] = @ptrCast(c.WGPUCommandBuffer, cmd.ptr);
|
|
}
|
|
break :blk few_commands[0..cmds.len];
|
|
} else blk: {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPUCommandBuffer, cmds.len) catch unreachable;
|
|
for (cmds) |cmd, i| {
|
|
mem[i] = @ptrCast(c.WGPUCommandBuffer, cmd.ptr);
|
|
}
|
|
break :blk mem;
|
|
};
|
|
defer if (cmds.len > 16) std.heap.page_allocator.free(cmds);
|
|
|
|
c.wgpuQueueSubmit(
|
|
wgpu_queue,
|
|
@intCast(u32, commands.len),
|
|
@ptrCast([*]c.WGPUCommandBuffer, commands.ptr),
|
|
);
|
|
}
|
|
}).submit,
|
|
.writeBuffer = (struct {
|
|
pub fn writeBuffer(ptr: *anyopaque, buffer: Buffer, buffer_offset: u64, data: *const anyopaque, size: u64) void {
|
|
c.wgpuQueueWriteBuffer(
|
|
@ptrCast(c.WGPUQueue, ptr),
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
buffer_offset,
|
|
data,
|
|
size,
|
|
);
|
|
}
|
|
}).writeBuffer,
|
|
.writeTexture = (struct {
|
|
pub fn writeTexture(
|
|
ptr: *anyopaque,
|
|
destination: *const ImageCopyTexture,
|
|
data: *const anyopaque,
|
|
data_size: usize,
|
|
data_layout: *const Texture.DataLayout,
|
|
write_size: *const Extent3D,
|
|
) void {
|
|
c.wgpuQueueWriteTexture(
|
|
@ptrCast(c.WGPUQueue, ptr),
|
|
&c.WGPUImageCopyTexture{
|
|
.nextInChain = null,
|
|
.texture = @ptrCast(c.WGPUTexture, destination.texture.ptr),
|
|
.mipLevel = destination.mip_level,
|
|
.origin = @bitCast(c.WGPUOrigin3D, destination.origin),
|
|
.aspect = @bitCast(c.WGPUTextureAspect, destination.aspect),
|
|
},
|
|
data,
|
|
data_size,
|
|
@ptrCast(*const c.WGPUTextureDataLayout, data_layout),
|
|
@ptrCast(*const c.WGPUExtent3D, write_size),
|
|
);
|
|
}
|
|
}).writeTexture,
|
|
};
|
|
|
|
fn wrapShaderModule(shader_module: c.WGPUShaderModule) ShaderModule {
|
|
return .{
|
|
.ptr = shader_module.?,
|
|
.vtable = &shader_module_vtable,
|
|
};
|
|
}
|
|
|
|
const shader_module_vtable = ShaderModule.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuShaderModuleReference(@ptrCast(c.WGPUShaderModule, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuShaderModuleRelease(@ptrCast(c.WGPUShaderModule, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuShaderModuleSetLabel(@ptrCast(c.WGPUShaderModule, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.getCompilationInfo = (struct {
|
|
pub fn getCompilationInfo(ptr: *anyopaque, callback: *ShaderModule.CompilationInfoCallback) void {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(status: c.WGPUCompilationInfoRequestStatus, info: [*c]const c.WGPUCompilationInfo, userdata: ?*anyopaque) callconv(.C) void {
|
|
const callback_info = @ptrCast(*ShaderModule.CompilationInfoCallback, @alignCast(std.meta.alignment(*ShaderModule.CompilationInfoCallback), userdata.?));
|
|
|
|
callback_info.type_erased_callback(
|
|
callback_info.type_erased_ctx,
|
|
@intToEnum(ShaderModule.CompilationInfoRequestStatus, status),
|
|
&ShaderModule.CompilationInfo{
|
|
.messages = @bitCast([]const ShaderModule.CompilationMessage, info[0].messages[0..info[0].messageCount]),
|
|
},
|
|
);
|
|
}
|
|
}).cCallback;
|
|
|
|
c.wgpuShaderModuleGetCompilationInfo(@ptrCast(c.WGPUShaderModule, ptr), cCallback, callback);
|
|
}
|
|
}).getCompilationInfo,
|
|
};
|
|
|
|
fn wrapSwapChain(swap_chain: c.WGPUSwapChain) SwapChain {
|
|
return .{
|
|
.ptr = swap_chain.?,
|
|
.vtable = &swap_chain_vtable,
|
|
};
|
|
}
|
|
|
|
const swap_chain_vtable = SwapChain.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuSwapChainReference(@ptrCast(c.WGPUSwapChain, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuSwapChainRelease(@ptrCast(c.WGPUSwapChain, ptr));
|
|
}
|
|
}).release,
|
|
.configure = (struct {
|
|
pub fn configure(ptr: *anyopaque, format: Texture.Format, allowed_usage: Texture.Usage, width: u32, height: u32) void {
|
|
c.wgpuSwapChainConfigure(
|
|
@ptrCast(c.WGPUSwapChain, ptr),
|
|
@enumToInt(format),
|
|
@bitCast(u32, allowed_usage),
|
|
width,
|
|
height,
|
|
);
|
|
}
|
|
}).configure,
|
|
.getCurrentTextureView = (struct {
|
|
pub fn getCurrentTextureView(ptr: *anyopaque) TextureView {
|
|
return wrapTextureView(c.wgpuSwapChainGetCurrentTextureView(@ptrCast(c.WGPUSwapChain, ptr)));
|
|
}
|
|
}).getCurrentTextureView,
|
|
.present = (struct {
|
|
pub fn present(ptr: *anyopaque) void {
|
|
c.wgpuSwapChainPresent(@ptrCast(c.WGPUSwapChain, ptr));
|
|
}
|
|
}).present,
|
|
};
|
|
|
|
fn wrapTextureView(texture_view: c.WGPUTextureView) TextureView {
|
|
return .{
|
|
.ptr = texture_view.?,
|
|
.vtable = &texture_view_vtable,
|
|
};
|
|
}
|
|
|
|
const texture_view_vtable = TextureView.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuTextureViewReference(@ptrCast(c.WGPUTextureView, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuTextureViewRelease(@ptrCast(c.WGPUTextureView, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuTextureViewSetLabel(@ptrCast(c.WGPUTextureView, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapTexture(texture: c.WGPUTexture) Texture {
|
|
return .{
|
|
.ptr = texture.?,
|
|
.vtable = &texture_vtable,
|
|
};
|
|
}
|
|
|
|
const texture_vtable = Texture.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuTextureReference(@ptrCast(c.WGPUTexture, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuTextureRelease(@ptrCast(c.WGPUTexture, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuTextureSetLabel(@ptrCast(c.WGPUTexture, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.destroy = (struct {
|
|
pub fn destroy(ptr: *anyopaque) void {
|
|
c.wgpuTextureDestroy(@ptrCast(c.WGPUTexture, ptr));
|
|
}
|
|
}).destroy,
|
|
.createView = (struct {
|
|
pub fn createView(ptr: *anyopaque, descriptor: *const TextureView.Descriptor) TextureView {
|
|
const desc = c.WGPUTextureViewDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else "",
|
|
.format = @enumToInt(descriptor.format),
|
|
.dimension = @enumToInt(descriptor.dimension),
|
|
.baseMipLevel = descriptor.base_mip_level,
|
|
.mipLevelCount = descriptor.mip_level_count,
|
|
.baseArrayLayer = descriptor.base_array_layer,
|
|
.arrayLayerCount = descriptor.array_layer_count,
|
|
.aspect = @enumToInt(descriptor.aspect),
|
|
};
|
|
return wrapTextureView(c.wgpuTextureCreateView(
|
|
@ptrCast(c.WGPUTexture, ptr),
|
|
&desc,
|
|
));
|
|
}
|
|
}).createView,
|
|
};
|
|
|
|
fn wrapSampler(sampler: c.WGPUSampler) Sampler {
|
|
return .{
|
|
.ptr = sampler.?,
|
|
.vtable = &sampler_vtable,
|
|
};
|
|
}
|
|
|
|
const sampler_vtable = Sampler.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuSamplerReference(@ptrCast(c.WGPUSampler, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuSamplerRelease(@ptrCast(c.WGPUSampler, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuSamplerSetLabel(@ptrCast(c.WGPUSampler, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapRenderPipeline(pipeline: c.WGPURenderPipeline) RenderPipeline {
|
|
return .{
|
|
.ptr = pipeline.?,
|
|
.vtable = &render_pipeline_vtable,
|
|
};
|
|
}
|
|
|
|
const render_pipeline_vtable = RenderPipeline.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuRenderPipelineReference(@ptrCast(c.WGPURenderPipeline, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuRenderPipelineRelease(@ptrCast(c.WGPURenderPipeline, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuRenderPipelineSetLabel(@ptrCast(c.WGPURenderPipeline, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.getBindGroupLayout = (struct {
|
|
pub fn getBindGroupLayout(ptr: *anyopaque, group_index: u32) BindGroupLayout {
|
|
return wrapBindGroupLayout(c.wgpuRenderPipelineGetBindGroupLayout(
|
|
@ptrCast(c.WGPURenderPipeline, ptr),
|
|
group_index,
|
|
));
|
|
}
|
|
}).getBindGroupLayout,
|
|
};
|
|
|
|
fn wrapRenderPassEncoder(pass: c.WGPURenderPassEncoder) RenderPassEncoder {
|
|
return .{
|
|
.ptr = pass.?,
|
|
.vtable = &render_pass_encoder_vtable,
|
|
};
|
|
}
|
|
|
|
const render_pass_encoder_vtable = RenderPassEncoder.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuRenderPassEncoderReference(@ptrCast(c.WGPURenderPassEncoder, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuRenderPassEncoderRelease(@ptrCast(c.WGPURenderPassEncoder, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuRenderPassEncoderSetLabel(@ptrCast(c.WGPURenderPassEncoder, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.setPipeline = (struct {
|
|
pub fn setPipeline(ptr: *anyopaque, pipeline: RenderPipeline) void {
|
|
c.wgpuRenderPassEncoderSetPipeline(@ptrCast(c.WGPURenderPassEncoder, ptr), @ptrCast(c.WGPURenderPipeline, pipeline.ptr));
|
|
}
|
|
}).setPipeline,
|
|
.draw = (struct {
|
|
pub fn draw(ptr: *anyopaque, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void {
|
|
c.wgpuRenderPassEncoderDraw(@ptrCast(c.WGPURenderPassEncoder, ptr), vertex_count, instance_count, first_vertex, first_instance);
|
|
}
|
|
}).draw,
|
|
.drawIndexed = (struct {
|
|
pub fn drawIndexed(
|
|
ptr: *anyopaque,
|
|
index_count: u32,
|
|
instance_count: u32,
|
|
first_index: u32,
|
|
base_vertex: i32,
|
|
first_instance: u32,
|
|
) void {
|
|
c.wgpuRenderPassEncoderDrawIndexed(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
index_count,
|
|
instance_count,
|
|
first_index,
|
|
base_vertex,
|
|
first_instance,
|
|
);
|
|
}
|
|
}).drawIndexed,
|
|
.drawIndexedIndirect = (struct {
|
|
pub fn drawIndexedIndirect(ptr: *anyopaque, indirect_buffer: Buffer, indirect_offset: u64) void {
|
|
c.wgpuRenderPassEncoderDrawIndexedIndirect(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, indirect_buffer.ptr),
|
|
indirect_offset,
|
|
);
|
|
}
|
|
}).drawIndexedIndirect,
|
|
.drawIndirect = (struct {
|
|
pub fn drawIndirect(ptr: *anyopaque, indirect_buffer: Buffer, indirect_offset: u64) void {
|
|
c.wgpuRenderPassEncoderDrawIndexedIndirect(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, indirect_buffer.ptr),
|
|
indirect_offset,
|
|
);
|
|
}
|
|
}).drawIndirect,
|
|
.beginOcclusionQuery = (struct {
|
|
pub fn beginOcclusionQuery(ptr: *anyopaque, query_index: u32) void {
|
|
c.wgpuRenderPassEncoderBeginOcclusionQuery(@ptrCast(c.WGPURenderPassEncoder, ptr), query_index);
|
|
}
|
|
}).beginOcclusionQuery,
|
|
.endOcclusionQuery = (struct {
|
|
pub fn endOcclusionQuery(ptr: *anyopaque) void {
|
|
c.wgpuRenderPassEncoderEndOcclusionQuery(@ptrCast(c.WGPURenderPassEncoder, ptr));
|
|
}
|
|
}).endOcclusionQuery,
|
|
.end = (struct {
|
|
pub fn end(ptr: *anyopaque) void {
|
|
c.wgpuRenderPassEncoderEnd(@ptrCast(c.WGPURenderPassEncoder, ptr));
|
|
}
|
|
}).end,
|
|
.executeBundles = (struct {
|
|
pub fn executeBundles(ptr: *anyopaque, bundles: []RenderBundle) void {
|
|
var few_bundles: [16]c.WGPURenderBundle = undefined;
|
|
const c_bundles = if (bundles.len <= 8) blk: {
|
|
for (bundles) |bundle, i| {
|
|
few_bundles[i] = @ptrCast(c.WGPURenderBundle, bundle.ptr);
|
|
}
|
|
break :blk few_bundles[0..bundles.len];
|
|
} else blk: {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPURenderBundle, bundles.len) catch unreachable;
|
|
for (bundles) |bundle, i| {
|
|
mem[i] = @ptrCast(c.WGPURenderBundle, bundle.ptr);
|
|
}
|
|
break :blk mem;
|
|
};
|
|
defer if (bundles.len > 8) std.heap.page_allocator.free(c_bundles);
|
|
|
|
c.wgpuRenderPassEncoderExecuteBundles(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@intCast(u32, c_bundles.len),
|
|
c_bundles.ptr,
|
|
);
|
|
}
|
|
}).executeBundles,
|
|
.insertDebugMarker = (struct {
|
|
pub fn insertDebugMarker(ptr: *anyopaque, marker_label: [*:0]const u8) void {
|
|
c.wgpuRenderPassEncoderInsertDebugMarker(@ptrCast(c.WGPURenderPassEncoder, ptr), marker_label);
|
|
}
|
|
}).insertDebugMarker,
|
|
.popDebugGroup = (struct {
|
|
pub fn popDebugGroup(ptr: *anyopaque) void {
|
|
c.wgpuRenderPassEncoderPopDebugGroup(@ptrCast(c.WGPURenderPassEncoder, ptr));
|
|
}
|
|
}).popDebugGroup,
|
|
.pushDebugGroup = (struct {
|
|
pub fn pushDebugGroup(ptr: *anyopaque, group_label: [*:0]const u8) void {
|
|
c.wgpuRenderPassEncoderPushDebugGroup(@ptrCast(c.WGPURenderPassEncoder, ptr), group_label);
|
|
}
|
|
}).pushDebugGroup,
|
|
.setBindGroup = (struct {
|
|
pub fn setBindGroup(
|
|
ptr: *anyopaque,
|
|
group_index: u32,
|
|
group: BindGroup,
|
|
dynamic_offsets: ?[]const u32,
|
|
) void {
|
|
c.wgpuRenderPassEncoderSetBindGroup(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
group_index,
|
|
@ptrCast(c.WGPUBindGroup, group.ptr),
|
|
if (dynamic_offsets) |d| @intCast(u32, d.len) else 0,
|
|
if (dynamic_offsets) |d| d.ptr else null,
|
|
);
|
|
}
|
|
}).setBindGroup,
|
|
.setBlendConstant = (struct {
|
|
pub fn setBlendConstant(ptr: *anyopaque, color: *const Color) void {
|
|
c.wgpuRenderPassEncoderSetBlendConstant(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@ptrCast(*const c.WGPUColor, color),
|
|
);
|
|
}
|
|
}).setBlendConstant,
|
|
.setIndexBuffer = (struct {
|
|
pub fn setIndexBuffer(
|
|
ptr: *anyopaque,
|
|
buffer: Buffer,
|
|
format: IndexFormat,
|
|
offset: u64,
|
|
size: u64,
|
|
) void {
|
|
c.wgpuRenderPassEncoderSetIndexBuffer(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
@enumToInt(format),
|
|
offset,
|
|
size,
|
|
);
|
|
}
|
|
}).setIndexBuffer,
|
|
.setScissorRect = (struct {
|
|
pub fn setScissorRect(ptr: *anyopaque, x: u32, y: u32, width: u32, height: u32) void {
|
|
c.wgpuRenderPassEncoderSetScissorRect(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
);
|
|
}
|
|
}).setScissorRect,
|
|
.setStencilReference = (struct {
|
|
pub fn setStencilReference(ptr: *anyopaque, reference: u32) void {
|
|
c.wgpuRenderPassEncoderSetStencilReference(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
reference,
|
|
);
|
|
}
|
|
}).setStencilReference,
|
|
.setVertexBuffer = (struct {
|
|
pub fn setVertexBuffer(ptr: *anyopaque, slot: u32, buffer: Buffer, offset: u64, size: u64) void {
|
|
c.wgpuRenderPassEncoderSetVertexBuffer(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
slot,
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
offset,
|
|
size,
|
|
);
|
|
}
|
|
}).setVertexBuffer,
|
|
.setViewport = (struct {
|
|
pub fn setViewport(
|
|
ptr: *anyopaque,
|
|
x: f32,
|
|
y: f32,
|
|
width: f32,
|
|
height: f32,
|
|
min_depth: f32,
|
|
max_depth: f32,
|
|
) void {
|
|
c.wgpuRenderPassEncoderSetViewport(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
min_depth,
|
|
max_depth,
|
|
);
|
|
}
|
|
}).setViewport,
|
|
.writeTimestamp = (struct {
|
|
pub fn writeTimestamp(ptr: *anyopaque, query_set: QuerySet, query_index: u32) void {
|
|
c.wgpuRenderPassEncoderWriteTimestamp(
|
|
@ptrCast(c.WGPURenderPassEncoder, ptr),
|
|
@ptrCast(c.WGPUQuerySet, query_set.ptr),
|
|
query_index,
|
|
);
|
|
}
|
|
}).writeTimestamp,
|
|
};
|
|
|
|
fn wrapRenderBundleEncoder(enc: c.WGPURenderBundleEncoder) RenderBundleEncoder {
|
|
return .{
|
|
.ptr = enc.?,
|
|
.vtable = &render_bundle_encoder_vtable,
|
|
};
|
|
}
|
|
|
|
const render_bundle_encoder_vtable = RenderBundleEncoder.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuRenderBundleEncoderReference(@ptrCast(c.WGPURenderBundleEncoder, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuRenderBundleEncoderRelease(@ptrCast(c.WGPURenderBundleEncoder, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuRenderBundleEncoderSetLabel(@ptrCast(c.WGPURenderBundleEncoder, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.setPipeline = (struct {
|
|
pub fn setPipeline(ptr: *anyopaque, pipeline: RenderPipeline) void {
|
|
c.wgpuRenderBundleEncoderSetPipeline(@ptrCast(c.WGPURenderBundleEncoder, ptr), @ptrCast(c.WGPURenderPipeline, pipeline.ptr));
|
|
}
|
|
}).setPipeline,
|
|
.draw = (struct {
|
|
pub fn draw(ptr: *anyopaque, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void {
|
|
c.wgpuRenderBundleEncoderDraw(@ptrCast(c.WGPURenderBundleEncoder, ptr), vertex_count, instance_count, first_vertex, first_instance);
|
|
}
|
|
}).draw,
|
|
.drawIndexed = (struct {
|
|
pub fn drawIndexed(
|
|
ptr: *anyopaque,
|
|
index_count: u32,
|
|
instance_count: u32,
|
|
first_index: u32,
|
|
base_vertex: i32,
|
|
first_instance: u32,
|
|
) void {
|
|
c.wgpuRenderBundleEncoderDrawIndexed(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
index_count,
|
|
instance_count,
|
|
first_index,
|
|
base_vertex,
|
|
first_instance,
|
|
);
|
|
}
|
|
}).drawIndexed,
|
|
.drawIndexedIndirect = (struct {
|
|
pub fn drawIndexedIndirect(ptr: *anyopaque, indirect_buffer: Buffer, indirect_offset: u64) void {
|
|
c.wgpuRenderBundleEncoderDrawIndexedIndirect(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, indirect_buffer.ptr),
|
|
indirect_offset,
|
|
);
|
|
}
|
|
}).drawIndexedIndirect,
|
|
.drawIndirect = (struct {
|
|
pub fn drawIndirect(ptr: *anyopaque, indirect_buffer: Buffer, indirect_offset: u64) void {
|
|
c.wgpuRenderBundleEncoderDrawIndexedIndirect(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, indirect_buffer.ptr),
|
|
indirect_offset,
|
|
);
|
|
}
|
|
}).drawIndirect,
|
|
.finish = (struct {
|
|
pub fn finish(ptr: *anyopaque, descriptor: *const RenderBundle.Descriptor) RenderBundle {
|
|
const desc = c.WGPURenderBundleDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (descriptor.label) |l| l else null,
|
|
};
|
|
return wrapRenderBundle(c.wgpuRenderBundleEncoderFinish(@ptrCast(c.WGPURenderBundleEncoder, ptr), &desc));
|
|
}
|
|
}).finish,
|
|
.insertDebugMarker = (struct {
|
|
pub fn insertDebugMarker(ptr: *anyopaque, marker_label: [*:0]const u8) void {
|
|
c.wgpuRenderBundleEncoderInsertDebugMarker(@ptrCast(c.WGPURenderBundleEncoder, ptr), marker_label);
|
|
}
|
|
}).insertDebugMarker,
|
|
.popDebugGroup = (struct {
|
|
pub fn popDebugGroup(ptr: *anyopaque) void {
|
|
c.wgpuRenderBundleEncoderPopDebugGroup(@ptrCast(c.WGPURenderBundleEncoder, ptr));
|
|
}
|
|
}).popDebugGroup,
|
|
.pushDebugGroup = (struct {
|
|
pub fn pushDebugGroup(ptr: *anyopaque, group_label: [*:0]const u8) void {
|
|
c.wgpuRenderBundleEncoderPushDebugGroup(@ptrCast(c.WGPURenderBundleEncoder, ptr), group_label);
|
|
}
|
|
}).pushDebugGroup,
|
|
.setBindGroup = (struct {
|
|
pub fn setBindGroup(
|
|
ptr: *anyopaque,
|
|
group_index: u32,
|
|
group: BindGroup,
|
|
dynamic_offsets: ?[]const u32,
|
|
) void {
|
|
c.wgpuRenderBundleEncoderSetBindGroup(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
group_index,
|
|
@ptrCast(c.WGPUBindGroup, group.ptr),
|
|
if (dynamic_offsets) |d| @intCast(u32, d.len) else 0,
|
|
if (dynamic_offsets) |d| d.ptr else null,
|
|
);
|
|
}
|
|
}).setBindGroup,
|
|
.setIndexBuffer = (struct {
|
|
pub fn setIndexBuffer(
|
|
ptr: *anyopaque,
|
|
buffer: Buffer,
|
|
format: IndexFormat,
|
|
offset: u64,
|
|
size: u64,
|
|
) void {
|
|
c.wgpuRenderBundleEncoderSetIndexBuffer(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
@enumToInt(format),
|
|
offset,
|
|
size,
|
|
);
|
|
}
|
|
}).setIndexBuffer,
|
|
.setVertexBuffer = (struct {
|
|
pub fn setVertexBuffer(ptr: *anyopaque, slot: u32, buffer: Buffer, offset: u64, size: u64) void {
|
|
c.wgpuRenderBundleEncoderSetVertexBuffer(
|
|
@ptrCast(c.WGPURenderBundleEncoder, ptr),
|
|
slot,
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
offset,
|
|
size,
|
|
);
|
|
}
|
|
}).setVertexBuffer,
|
|
};
|
|
|
|
fn wrapRenderBundle(bundle: c.WGPURenderBundle) RenderBundle {
|
|
return .{
|
|
.ptr = bundle.?,
|
|
.vtable = &render_bundle_vtable,
|
|
};
|
|
}
|
|
|
|
const render_bundle_vtable = RenderBundle.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuRenderBundleReference(@ptrCast(c.WGPURenderBundle, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuRenderBundleRelease(@ptrCast(c.WGPURenderBundle, ptr));
|
|
}
|
|
}).release,
|
|
};
|
|
|
|
fn wrapQuerySet(qset: c.WGPUQuerySet) QuerySet {
|
|
return .{
|
|
.ptr = qset.?,
|
|
.vtable = &query_set_vtable,
|
|
};
|
|
}
|
|
|
|
const query_set_vtable = QuerySet.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuQuerySetReference(@ptrCast(c.WGPUQuerySet, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuQuerySetRelease(@ptrCast(c.WGPUQuerySet, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuQuerySetSetLabel(@ptrCast(c.WGPUQuerySet, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.destroy = (struct {
|
|
pub fn destroy(ptr: *anyopaque) void {
|
|
c.wgpuQuerySetDestroy(@ptrCast(c.WGPUQuerySet, ptr));
|
|
}
|
|
}).destroy,
|
|
};
|
|
|
|
fn wrapPipelineLayout(layout: c.WGPUPipelineLayout) PipelineLayout {
|
|
return .{
|
|
.ptr = layout.?,
|
|
.vtable = &pipeline_layout_vtable,
|
|
};
|
|
}
|
|
|
|
const pipeline_layout_vtable = PipelineLayout.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuPipelineLayoutReference(@ptrCast(c.WGPUPipelineLayout, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuPipelineLayoutRelease(@ptrCast(c.WGPUPipelineLayout, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuPipelineLayoutSetLabel(@ptrCast(c.WGPUPipelineLayout, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapExternalTexture(texture: c.WGPUExternalTexture) ExternalTexture {
|
|
return .{
|
|
.ptr = texture.?,
|
|
.vtable = &external_texture_vtable,
|
|
};
|
|
}
|
|
|
|
const external_texture_vtable = ExternalTexture.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuExternalTextureReference(@ptrCast(c.WGPUExternalTexture, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuExternalTextureRelease(@ptrCast(c.WGPUExternalTexture, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuExternalTextureSetLabel(@ptrCast(c.WGPUExternalTexture, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.destroy = (struct {
|
|
pub fn destroy(ptr: *anyopaque) void {
|
|
c.wgpuExternalTextureDestroy(@ptrCast(c.WGPUExternalTexture, ptr));
|
|
}
|
|
}).destroy,
|
|
};
|
|
|
|
fn wrapBindGroup(group: c.WGPUBindGroup) BindGroup {
|
|
return .{
|
|
.ptr = group.?,
|
|
.vtable = &bind_group_vtable,
|
|
};
|
|
}
|
|
|
|
const bind_group_vtable = BindGroup.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuBindGroupReference(@ptrCast(c.WGPUBindGroup, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuBindGroupRelease(@ptrCast(c.WGPUBindGroup, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuBindGroupSetLabel(@ptrCast(c.WGPUBindGroup, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapBindGroupLayout(layout: c.WGPUBindGroupLayout) BindGroupLayout {
|
|
return .{
|
|
.ptr = layout.?,
|
|
.vtable = &bind_group_layout_vtable,
|
|
};
|
|
}
|
|
|
|
const bind_group_layout_vtable = BindGroupLayout.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuBindGroupLayoutReference(@ptrCast(c.WGPUBindGroupLayout, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuBindGroupLayoutRelease(@ptrCast(c.WGPUBindGroupLayout, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuBindGroupLayoutSetLabel(@ptrCast(c.WGPUBindGroupLayout, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapBuffer(buffer: c.WGPUBuffer) Buffer {
|
|
return .{
|
|
.ptr = buffer.?,
|
|
.vtable = &buffer_vtable,
|
|
};
|
|
}
|
|
|
|
const buffer_vtable = Buffer.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuBufferReference(@ptrCast(c.WGPUBuffer, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuBufferRelease(@ptrCast(c.WGPUBuffer, ptr));
|
|
}
|
|
}).release,
|
|
.getConstMappedRange = (struct {
|
|
pub fn getConstMappedRange(ptr: *anyopaque, offset: usize, size: usize) []const u8 {
|
|
const range = c.wgpuBufferGetConstMappedRange(@ptrCast(c.WGPUBuffer, ptr), offset, size);
|
|
return @ptrCast([*c]const u8, range.?)[0..size];
|
|
}
|
|
}).getConstMappedRange,
|
|
.getMappedRange = (struct {
|
|
pub fn getMappedRange(ptr: *anyopaque, offset: usize, size: usize) []u8 {
|
|
const range = c.wgpuBufferGetMappedRange(@ptrCast(c.WGPUBuffer, ptr), offset, size);
|
|
return @ptrCast([*c]u8, range.?)[0..size];
|
|
}
|
|
}).getMappedRange,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuBufferSetLabel(@ptrCast(c.WGPUBuffer, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.destroy = (struct {
|
|
pub fn destroy(ptr: *anyopaque) void {
|
|
c.wgpuBufferDestroy(@ptrCast(c.WGPUBuffer, ptr));
|
|
}
|
|
}).destroy,
|
|
.mapAsync = (struct {
|
|
pub fn mapAsync(
|
|
ptr: *anyopaque,
|
|
mode: Buffer.MapMode,
|
|
offset: usize,
|
|
size: usize,
|
|
callback: *Buffer.MapCallback,
|
|
) void {
|
|
const cCallback = (struct {
|
|
pub fn cCallback(status: c.WGPUBufferMapAsyncStatus, userdata: ?*anyopaque) callconv(.C) void {
|
|
const callback_info = @ptrCast(*Buffer.MapCallback, @alignCast(std.meta.alignment(*Buffer.MapCallback), userdata.?));
|
|
callback_info.type_erased_callback(callback_info.type_erased_ctx, @intToEnum(Buffer.MapAsyncStatus, status));
|
|
}
|
|
}).cCallback;
|
|
c.wgpuBufferMapAsync(@ptrCast(c.WGPUBuffer, ptr), @enumToInt(mode), offset, size, cCallback, callback);
|
|
}
|
|
}).mapAsync,
|
|
.unmap = (struct {
|
|
pub fn unmap(ptr: *anyopaque) void {
|
|
c.wgpuBufferUnmap(@ptrCast(c.WGPUBuffer, ptr));
|
|
}
|
|
}).unmap,
|
|
};
|
|
|
|
fn wrapCommandBuffer(buffer: c.WGPUCommandBuffer) CommandBuffer {
|
|
return .{
|
|
.ptr = buffer.?,
|
|
.vtable = &command_buffer_vtable,
|
|
};
|
|
}
|
|
|
|
const command_buffer_vtable = CommandBuffer.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuCommandBufferReference(@ptrCast(c.WGPUCommandBuffer, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuCommandBufferRelease(@ptrCast(c.WGPUCommandBuffer, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuCommandBufferSetLabel(@ptrCast(c.WGPUCommandBuffer, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
};
|
|
|
|
fn wrapCommandEncoder(enc: c.WGPUCommandEncoder) CommandEncoder {
|
|
return .{
|
|
.ptr = enc.?,
|
|
.vtable = &command_encoder_vtable,
|
|
};
|
|
}
|
|
|
|
const command_encoder_vtable = CommandEncoder.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuCommandEncoderReference(@ptrCast(c.WGPUCommandEncoder, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuCommandEncoderRelease(@ptrCast(c.WGPUCommandEncoder, ptr));
|
|
}
|
|
}).release,
|
|
.finish = (struct {
|
|
pub fn finish(ptr: *anyopaque, descriptor: ?*const CommandBuffer.Descriptor) CommandBuffer {
|
|
const desc: ?*c.WGPUCommandBufferDescriptor = if (descriptor) |d| &.{
|
|
.nextInChain = null,
|
|
.label = if (d.label) |l| l else "",
|
|
} else null;
|
|
return wrapCommandBuffer(c.wgpuCommandEncoderFinish(@ptrCast(c.WGPUCommandEncoder, ptr), desc));
|
|
}
|
|
}).finish,
|
|
.injectValidationError = (struct {
|
|
pub fn injectValidationError(ptr: *anyopaque, message: [*:0]const u8) void {
|
|
c.wgpuCommandEncoderInjectValidationError(@ptrCast(c.WGPUCommandEncoder, ptr), message);
|
|
}
|
|
}).injectValidationError,
|
|
.insertDebugMarker = (struct {
|
|
pub fn insertDebugMarker(ptr: *anyopaque, marker_label: [*:0]const u8) void {
|
|
c.wgpuCommandEncoderInsertDebugMarker(@ptrCast(c.WGPUCommandEncoder, ptr), marker_label);
|
|
}
|
|
}).insertDebugMarker,
|
|
.resolveQuerySet = (struct {
|
|
pub fn resolveQuerySet(
|
|
ptr: *anyopaque,
|
|
query_set: QuerySet,
|
|
first_query: u32,
|
|
query_count: u32,
|
|
destination: Buffer,
|
|
destination_offset: u64,
|
|
) void {
|
|
c.wgpuCommandEncoderResolveQuerySet(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
@ptrCast(c.WGPUQuerySet, query_set.ptr),
|
|
first_query,
|
|
query_count,
|
|
@ptrCast(c.WGPUBuffer, destination.ptr),
|
|
destination_offset,
|
|
);
|
|
}
|
|
}).resolveQuerySet,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuCommandEncoderSetLabel(@ptrCast(c.WGPUCommandEncoder, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.beginComputePass = (struct {
|
|
pub fn beginComputePass(ptr: *anyopaque, descriptor: ?*const ComputePassEncoder.Descriptor) ComputePassEncoder {
|
|
if (descriptor) |d| {
|
|
var few_timestamp_writes: [8]c.WGPUComputePassTimestampWrite = undefined;
|
|
const timestamp_writes = if (d.timestamp_writes.len <= 8) blk: {
|
|
for (d.timestamp_writes) |v, i| {
|
|
few_timestamp_writes[i] = c.WGPUComputePassTimestampWrite{
|
|
.querySet = @ptrCast(c.WGPUQuerySet, v.query_set.ptr),
|
|
.queryIndex = v.query_index,
|
|
.location = @enumToInt(v.location),
|
|
};
|
|
}
|
|
break :blk few_timestamp_writes[0..d.timestamp_writes.len];
|
|
} else blk: {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPUComputePassTimestampWrite, d.timestamp_writes.len) catch unreachable;
|
|
for (d.timestamp_writes) |v, i| {
|
|
mem[i] = c.WGPUComputePassTimestampWrite{
|
|
.querySet = @ptrCast(c.WGPUQuerySet, v.query_set.ptr),
|
|
.queryIndex = v.query_index,
|
|
.location = @enumToInt(v.location),
|
|
};
|
|
}
|
|
break :blk mem;
|
|
};
|
|
defer if (d.timestamp_writes.len > 8) std.heap.page_allocator.free(timestamp_writes);
|
|
|
|
const desc = c.WGPUComputePassDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (d.label) |l| l else null,
|
|
.timestampWriteCount = @intCast(u32, timestamp_writes.len),
|
|
.timestampWrites = @ptrCast([*]const c.WGPUComputePassTimestampWrite, timestamp_writes.ptr),
|
|
};
|
|
return wrapComputePassEncoder(c.wgpuCommandEncoderBeginComputePass(@ptrCast(c.WGPUCommandEncoder, ptr), &desc));
|
|
} else {
|
|
return wrapComputePassEncoder(c.wgpuCommandEncoderBeginComputePass(@ptrCast(c.WGPUCommandEncoder, ptr), null));
|
|
}
|
|
}
|
|
}).beginComputePass,
|
|
.beginRenderPass = (struct {
|
|
pub fn beginRenderPass(ptr: *anyopaque, d: *const RenderPassEncoder.Descriptor) RenderPassEncoder {
|
|
var few_color_attachments: [8]c.WGPURenderPassColorAttachment = undefined;
|
|
const color_attachments = if (d.color_attachments.len <= 8) blk: {
|
|
for (d.color_attachments) |v, i| {
|
|
few_color_attachments[i] = c.WGPURenderPassColorAttachment{
|
|
.view = @ptrCast(c.WGPUTextureView, v.view.ptr),
|
|
.resolveTarget = if (v.resolve_target) |t| @ptrCast(c.WGPUTextureView, t.ptr) else null,
|
|
.loadOp = @enumToInt(v.load_op),
|
|
.storeOp = @enumToInt(v.store_op),
|
|
.clearValue = @bitCast(c.WGPUColor, v.clear_value),
|
|
// deprecated:
|
|
.clearColor = c.WGPUColor{
|
|
.r = std.math.nan(f32),
|
|
.g = std.math.nan(f32),
|
|
.b = std.math.nan(f32),
|
|
.a = std.math.nan(f32),
|
|
},
|
|
};
|
|
}
|
|
break :blk few_color_attachments[0..d.color_attachments.len];
|
|
} else blk: {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPURenderPassColorAttachment, d.color_attachments.len) catch unreachable;
|
|
for (d.color_attachments) |v, i| {
|
|
mem[i] = c.WGPURenderPassColorAttachment{
|
|
.view = @ptrCast(c.WGPUTextureView, v.view.ptr),
|
|
.resolveTarget = if (v.resolve_target) |t| @ptrCast(c.WGPUTextureView, t.ptr) else null,
|
|
.loadOp = @enumToInt(v.load_op),
|
|
.storeOp = @enumToInt(v.store_op),
|
|
.clearValue = @bitCast(c.WGPUColor, v.clear_value),
|
|
// deprecated:
|
|
.clearColor = c.WGPUColor{
|
|
.r = std.math.nan(f32),
|
|
.g = std.math.nan(f32),
|
|
.b = std.math.nan(f32),
|
|
.a = std.math.nan(f32),
|
|
},
|
|
};
|
|
}
|
|
break :blk mem;
|
|
};
|
|
defer if (d.color_attachments.len > 8) std.heap.page_allocator.free(color_attachments);
|
|
|
|
var few_timestamp_writes: [8]c.WGPURenderPassTimestampWrite = undefined;
|
|
const timestamp_writes = if (d.timestamp_writes) |writes| blk: {
|
|
if (writes.len <= 8) {
|
|
for (writes) |v, i| {
|
|
few_timestamp_writes[i] = c.WGPURenderPassTimestampWrite{
|
|
.querySet = @ptrCast(c.WGPUQuerySet, v.query_set.ptr),
|
|
.queryIndex = v.query_index,
|
|
.location = @enumToInt(v.location),
|
|
};
|
|
}
|
|
break :blk few_timestamp_writes[0..writes.len];
|
|
} else {
|
|
const mem = std.heap.page_allocator.alloc(c.WGPURenderPassTimestampWrite, writes.len) catch unreachable;
|
|
for (writes) |v, i| {
|
|
mem[i] = c.WGPURenderPassTimestampWrite{
|
|
.querySet = @ptrCast(c.WGPUQuerySet, v.query_set.ptr),
|
|
.queryIndex = v.query_index,
|
|
.location = @enumToInt(v.location),
|
|
};
|
|
}
|
|
break :blk mem;
|
|
}
|
|
} else null;
|
|
defer if (timestamp_writes != null and timestamp_writes.?.len > 8) std.heap.page_allocator.free(timestamp_writes.?);
|
|
|
|
const desc = c.WGPURenderPassDescriptor{
|
|
.nextInChain = null,
|
|
.label = if (d.label) |l| l else null,
|
|
.colorAttachmentCount = @intCast(u32, color_attachments.len),
|
|
.colorAttachments = color_attachments.ptr,
|
|
.depthStencilAttachment = if (d.depth_stencil_attachment) |v| &c.WGPURenderPassDepthStencilAttachment{
|
|
.view = @ptrCast(c.WGPUTextureView, v.view.ptr),
|
|
.depthLoadOp = @enumToInt(v.depth_load_op),
|
|
.depthStoreOp = @enumToInt(v.depth_store_op),
|
|
.clearDepth = v.clear_depth,
|
|
.depthClearValue = v.depth_clear_value,
|
|
.depthReadOnly = v.depth_read_only,
|
|
.stencilLoadOp = @enumToInt(v.stencil_load_op),
|
|
.stencilStoreOp = @enumToInt(v.stencil_store_op),
|
|
.clearStencil = v.clear_stencil,
|
|
.stencilClearValue = v.stencil_clear_value,
|
|
.stencilReadOnly = v.stencil_read_only,
|
|
} else null,
|
|
.occlusionQuerySet = if (d.occlusion_query_set) |v| @ptrCast(c.WGPUQuerySet, v.ptr) else null,
|
|
.timestampWriteCount = if (timestamp_writes) |v| @intCast(u32, v.len) else 0,
|
|
.timestampWrites = if (timestamp_writes) |v| @ptrCast([*]const c.WGPURenderPassTimestampWrite, v.ptr) else null,
|
|
};
|
|
return wrapRenderPassEncoder(c.wgpuCommandEncoderBeginRenderPass(@ptrCast(c.WGPUCommandEncoder, ptr), &desc));
|
|
}
|
|
}).beginRenderPass,
|
|
.clearBuffer = (struct {
|
|
pub fn clearBuffer(ptr: *anyopaque, buffer: Buffer, offset: u64, size: u64) void {
|
|
c.wgpuCommandEncoderClearBuffer(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
offset,
|
|
size,
|
|
);
|
|
}
|
|
}).clearBuffer,
|
|
.copyBufferToBuffer = (struct {
|
|
pub fn copyBufferToBuffer(
|
|
ptr: *anyopaque,
|
|
source: Buffer,
|
|
source_offset: u64,
|
|
destination: Buffer,
|
|
destination_offset: u64,
|
|
size: u64,
|
|
) void {
|
|
c.wgpuCommandEncoderCopyBufferToBuffer(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, source.ptr),
|
|
source_offset,
|
|
@ptrCast(c.WGPUBuffer, destination.ptr),
|
|
destination_offset,
|
|
size,
|
|
);
|
|
}
|
|
}).copyBufferToBuffer,
|
|
.copyBufferToTexture = (struct {
|
|
pub fn copyBufferToTexture(
|
|
ptr: *anyopaque,
|
|
source: *const ImageCopyBuffer,
|
|
destination: *const ImageCopyTexture,
|
|
copy_size: *const Extent3D,
|
|
) void {
|
|
c.wgpuCommandEncoderCopyBufferToTexture(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
&convertImageCopyBuffer(source),
|
|
&convertImageCopyTexture(destination),
|
|
@ptrCast(*const c.WGPUExtent3D, copy_size),
|
|
);
|
|
}
|
|
}).copyBufferToTexture,
|
|
.copyTextureToBuffer = (struct {
|
|
pub fn copyTextureToBuffer(
|
|
ptr: *anyopaque,
|
|
source: *const ImageCopyTexture,
|
|
destination: *const ImageCopyBuffer,
|
|
copy_size: *const Extent3D,
|
|
) void {
|
|
c.wgpuCommandEncoderCopyTextureToBuffer(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
&convertImageCopyTexture(source),
|
|
&convertImageCopyBuffer(destination),
|
|
@ptrCast(*const c.WGPUExtent3D, copy_size),
|
|
);
|
|
}
|
|
}).copyTextureToBuffer,
|
|
.copyTextureToTexture = (struct {
|
|
pub fn copyTextureToTexture(
|
|
ptr: *anyopaque,
|
|
source: *const ImageCopyTexture,
|
|
destination: *const ImageCopyTexture,
|
|
copy_size: *const Extent3D,
|
|
) void {
|
|
c.wgpuCommandEncoderCopyTextureToTexture(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
&convertImageCopyTexture(source),
|
|
&convertImageCopyTexture(destination),
|
|
@ptrCast(*const c.WGPUExtent3D, copy_size),
|
|
);
|
|
}
|
|
}).copyTextureToTexture,
|
|
.popDebugGroup = (struct {
|
|
pub fn popDebugGroup(ptr: *anyopaque) void {
|
|
c.wgpuCommandEncoderPopDebugGroup(@ptrCast(c.WGPUCommandEncoder, ptr));
|
|
}
|
|
}).popDebugGroup,
|
|
.pushDebugGroup = (struct {
|
|
pub fn pushDebugGroup(ptr: *anyopaque, group_label: [*:0]const u8) void {
|
|
c.wgpuCommandEncoderPushDebugGroup(@ptrCast(c.WGPUCommandEncoder, ptr), group_label);
|
|
}
|
|
}).pushDebugGroup,
|
|
.writeBuffer = (struct {
|
|
pub fn writeBuffer(ptr: *anyopaque, buffer: Buffer, buffer_offset: u64, data: [*]const u8, size: u64) void {
|
|
c.wgpuCommandEncoderWriteBuffer(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, buffer.ptr),
|
|
buffer_offset,
|
|
data,
|
|
size,
|
|
);
|
|
}
|
|
}).writeBuffer,
|
|
.writeTimestamp = (struct {
|
|
pub fn writeTimestamp(ptr: *anyopaque, query_set: QuerySet, query_index: u32) void {
|
|
c.wgpuCommandEncoderWriteTimestamp(
|
|
@ptrCast(c.WGPUCommandEncoder, ptr),
|
|
@ptrCast(c.WGPUQuerySet, query_set.ptr),
|
|
query_index,
|
|
);
|
|
}
|
|
}).writeTimestamp,
|
|
};
|
|
|
|
inline fn convertImageCopyBuffer(v: *const ImageCopyBuffer) c.WGPUImageCopyBuffer {
|
|
return .{
|
|
.nextInChain = null,
|
|
.layout = convertTextureDataLayout(v.layout),
|
|
.buffer = @ptrCast(c.WGPUBuffer, v.buffer.ptr),
|
|
};
|
|
}
|
|
|
|
inline fn convertImageCopyTexture(v: *const ImageCopyTexture) c.WGPUImageCopyTexture {
|
|
return .{
|
|
.nextInChain = null,
|
|
.texture = @ptrCast(c.WGPUTexture, v.texture.ptr),
|
|
.mipLevel = v.mip_level,
|
|
.origin = @bitCast(c.WGPUOrigin3D, v.origin),
|
|
.aspect = @enumToInt(v.aspect),
|
|
};
|
|
}
|
|
|
|
inline fn convertTextureDataLayout(v: Texture.DataLayout) c.WGPUTextureDataLayout {
|
|
return .{
|
|
.nextInChain = null,
|
|
.offset = v.offset,
|
|
.bytesPerRow = v.bytes_per_row,
|
|
.rowsPerImage = v.rows_per_image,
|
|
};
|
|
}
|
|
|
|
fn wrapComputePassEncoder(enc: c.WGPUComputePassEncoder) ComputePassEncoder {
|
|
return .{
|
|
.ptr = enc.?,
|
|
.vtable = &compute_pass_encoder_vtable,
|
|
};
|
|
}
|
|
|
|
const compute_pass_encoder_vtable = ComputePassEncoder.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuComputePassEncoderReference(@ptrCast(c.WGPUComputePassEncoder, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuComputePassEncoderRelease(@ptrCast(c.WGPUComputePassEncoder, ptr));
|
|
}
|
|
}).release,
|
|
.dispatch = (struct {
|
|
pub fn dispatch(
|
|
ptr: *anyopaque,
|
|
workgroup_count_x: u32,
|
|
workgroup_count_y: u32,
|
|
workgroup_count_z: u32,
|
|
) void {
|
|
c.wgpuComputePassEncoderDispatch(
|
|
@ptrCast(c.WGPUComputePassEncoder, ptr),
|
|
workgroup_count_x,
|
|
workgroup_count_y,
|
|
workgroup_count_z,
|
|
);
|
|
}
|
|
}).dispatch,
|
|
.dispatchIndirect = (struct {
|
|
pub fn dispatchIndirect(
|
|
ptr: *anyopaque,
|
|
indirect_buffer: Buffer,
|
|
indirect_offset: u64,
|
|
) void {
|
|
c.wgpuComputePassEncoderDispatchIndirect(
|
|
@ptrCast(c.WGPUComputePassEncoder, ptr),
|
|
@ptrCast(c.WGPUBuffer, indirect_buffer.ptr),
|
|
indirect_offset,
|
|
);
|
|
}
|
|
}).dispatchIndirect,
|
|
.end = (struct {
|
|
pub fn end(ptr: *anyopaque) void {
|
|
c.wgpuComputePassEncoderEnd(@ptrCast(c.WGPUComputePassEncoder, ptr));
|
|
}
|
|
}).end,
|
|
.setBindGroup = (struct {
|
|
pub fn setBindGroup(
|
|
ptr: *anyopaque,
|
|
group_index: u32,
|
|
group: BindGroup,
|
|
dynamic_offsets: ?[]const u32,
|
|
) void {
|
|
c.wgpuComputePassEncoderSetBindGroup(
|
|
@ptrCast(c.WGPUComputePassEncoder, ptr),
|
|
group_index,
|
|
@ptrCast(c.WGPUBindGroup, group.ptr),
|
|
if (dynamic_offsets) |d| @intCast(u32, d.len) else 0,
|
|
if (dynamic_offsets) |d| d.ptr else null,
|
|
);
|
|
}
|
|
}).setBindGroup,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuComputePassEncoderSetLabel(@ptrCast(c.WGPUComputePassEncoder, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.insertDebugMarker = (struct {
|
|
pub fn insertDebugMarker(ptr: *anyopaque, marker_label: [*:0]const u8) void {
|
|
c.wgpuComputePassEncoderInsertDebugMarker(@ptrCast(c.WGPUComputePassEncoder, ptr), marker_label);
|
|
}
|
|
}).insertDebugMarker,
|
|
.popDebugGroup = (struct {
|
|
pub fn popDebugGroup(ptr: *anyopaque) void {
|
|
c.wgpuComputePassEncoderPopDebugGroup(@ptrCast(c.WGPUComputePassEncoder, ptr));
|
|
}
|
|
}).popDebugGroup,
|
|
.pushDebugGroup = (struct {
|
|
pub fn pushDebugGroup(ptr: *anyopaque, group_label: [*:0]const u8) void {
|
|
c.wgpuComputePassEncoderPushDebugGroup(@ptrCast(c.WGPUComputePassEncoder, ptr), group_label);
|
|
}
|
|
}).pushDebugGroup,
|
|
.setPipeline = (struct {
|
|
pub fn setPipeline(ptr: *anyopaque, pipeline: ComputePipeline) void {
|
|
c.wgpuComputePassEncoderSetPipeline(@ptrCast(c.WGPUComputePassEncoder, ptr), @ptrCast(c.WGPUComputePipeline, pipeline.ptr));
|
|
}
|
|
}).setPipeline,
|
|
.writeTimestamp = (struct {
|
|
pub fn writeTimestamp(ptr: *anyopaque, query_set: QuerySet, query_index: u32) void {
|
|
c.wgpuComputePassEncoderWriteTimestamp(
|
|
@ptrCast(c.WGPUComputePassEncoder, ptr),
|
|
@ptrCast(c.WGPUQuerySet, query_set.ptr),
|
|
query_index,
|
|
);
|
|
}
|
|
}).writeTimestamp,
|
|
};
|
|
|
|
fn wrapComputePipeline(pipeline: c.WGPUComputePipeline) ComputePipeline {
|
|
return .{
|
|
.ptr = pipeline.?,
|
|
.vtable = &compute_pipeline_vtable,
|
|
};
|
|
}
|
|
|
|
const compute_pipeline_vtable = ComputePipeline.VTable{
|
|
.reference = (struct {
|
|
pub fn reference(ptr: *anyopaque) void {
|
|
c.wgpuComputePipelineReference(@ptrCast(c.WGPUComputePipeline, ptr));
|
|
}
|
|
}).reference,
|
|
.release = (struct {
|
|
pub fn release(ptr: *anyopaque) void {
|
|
c.wgpuComputePipelineRelease(@ptrCast(c.WGPUComputePipeline, ptr));
|
|
}
|
|
}).release,
|
|
.setLabel = (struct {
|
|
pub fn setLabel(ptr: *anyopaque, label: [:0]const u8) void {
|
|
c.wgpuComputePipelineSetLabel(@ptrCast(c.WGPUComputePipeline, ptr), label);
|
|
}
|
|
}).setLabel,
|
|
.getBindGroupLayout = (struct {
|
|
pub fn getBindGroupLayout(ptr: *anyopaque, group_index: u32) BindGroupLayout {
|
|
return wrapBindGroupLayout(c.wgpuComputePipelineGetBindGroupLayout(
|
|
@ptrCast(c.WGPUComputePipeline, ptr),
|
|
group_index,
|
|
));
|
|
}
|
|
}).getBindGroupLayout,
|
|
};
|
|
|
|
test {
|
|
_ = wrap;
|
|
_ = interface_vtable;
|
|
_ = interface;
|
|
_ = createSurface;
|
|
_ = surface_vtable;
|
|
_ = adapter_vtable;
|
|
_ = wrapDevice;
|
|
_ = device_vtable;
|
|
_ = wrapQueue;
|
|
_ = wrapShaderModule;
|
|
_ = wrapSwapChain;
|
|
_ = wrapTextureView;
|
|
_ = wrapTexture;
|
|
_ = wrapSampler;
|
|
_ = wrapRenderPipeline;
|
|
_ = wrapRenderPassEncoder;
|
|
_ = wrapRenderBundleEncoder;
|
|
_ = wrapRenderBundle;
|
|
_ = wrapQuerySet;
|
|
_ = wrapPipelineLayout;
|
|
_ = wrapExternalTexture;
|
|
_ = wrapBindGroup;
|
|
_ = wrapBindGroupLayout;
|
|
_ = wrapBuffer;
|
|
_ = wrapCommandBuffer;
|
|
_ = wrapCommandEncoder;
|
|
_ = wrapComputePassEncoder;
|
|
_ = wrapComputePipeline;
|
|
}
|