src/gpu: move github.com/hexops/mach-gpu here

This moves github.com/hexops/mach-gpu@528dad0823dafeae5d474c88cc658b091bf2e605 to
this repository in the src/gpu directory. It can be imported via `@import("mach").gpu`.

Soon we will move away from mach-gpu entirely as part of #1166 - but in the meantime
I am giving a workshop at https://sycl.it and it would be nice for people using the
`mach.gpu.*` API to be able to search the API in this single repository.

There's not much harm to moving this code here.

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-04-13 11:25:41 -07:00
parent c45606c290
commit 2cf68adcc7
38 changed files with 8123 additions and 18 deletions

View file

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const glfw = @import("mach_glfw"); const glfw = @import("mach_glfw");
const gpu = @import("mach_gpu");
const sysgpu = @import("mach_sysgpu");
pub const SysgpuBackend = enum { pub const SysgpuBackend = enum {
default, default,
@ -101,12 +99,6 @@ pub fn build(b: *std.Build) !void {
try buildExamples(b, optimize, target, module); try buildExamples(b, optimize, target, module);
} }
if (want_core) { if (want_core) {
const mach_gpu_dep = b.dependency("mach_gpu", .{
.target = target,
.optimize = optimize,
});
module.addImport("mach-gpu", mach_gpu_dep.module("mach-gpu"));
if (target.result.cpu.arch == .wasm32) { if (target.result.cpu.arch == .wasm32) {
const sysjs_dep = b.dependency("mach_sysjs", .{ const sysjs_dep = b.dependency("mach_sysjs", .{
.target = target, .target = target,
@ -265,6 +257,37 @@ pub fn build(b: *std.Build) !void {
b.installArtifact(lib); b.installArtifact(lib);
} }
if (true) { // want_gpu
const gpu_dawn = @import("mach_gpu_dawn");
gpu_dawn.addPathsToModule(b, module, .{});
module.addIncludePath(.{ .path = sdkPath("/src/gpu") });
const example_exe = b.addExecutable(.{
.name = "dawn-gpu-hello-triangle",
.root_source_file = .{ .path = "src/gpu/example/main.zig" },
.target = target,
.optimize = optimize,
});
example_exe.root_module.addImport("mach", module);
link(b, example_exe, &example_exe.root_module);
const mach_glfw_dep = b.dependency("mach_glfw", .{
.target = target,
.optimize = optimize,
});
example_exe.root_module.addImport("mach-glfw", mach_glfw_dep.module("mach-glfw"));
const example_compile_step = b.step("dawn-gpu-hello-triangle", "Install 'dawn-gpu-hello-triangle'");
example_compile_step.dependOn(b.getInstallStep());
const example_run_cmd = b.addRunArtifact(example_exe);
example_run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| example_run_cmd.addArgs(args);
const example_run_step = b.step("run-dawn-gpu-hello-triangle", "Run 'dawn-gpu-hello-triangle' example");
example_run_step.dependOn(&example_run_cmd.step);
}
if (target.result.cpu.arch != .wasm32) { if (target.result.cpu.arch != .wasm32) {
// Creates a step for unit testing. This only builds the test executable // Creates a step for unit testing. This only builds the test executable
// but does not run it. // but does not run it.
@ -288,7 +311,7 @@ pub fn build(b: *std.Build) !void {
const test_step = b.step("test", "Run unit tests"); const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step); test_step.dependOn(&run_unit_tests.step);
if (want_sysgpu) linkSysgpu(b, &unit_tests.root_module); if (want_sysgpu) linkSysgpu(b, &unit_tests.root_module) else link(b, unit_tests, &unit_tests.root_module);
} }
} }
@ -507,10 +530,23 @@ pub const CoreApp = struct {
// TODO(sysgpu): remove this once we switch to sysgpu fully // TODO(sysgpu): remove this once we switch to sysgpu fully
pub fn link(mach_builder: *std.Build, step: *std.Build.Step.Compile, mod: *std.Build.Module) void { pub fn link(mach_builder: *std.Build, step: *std.Build.Step.Compile, mod: *std.Build.Module) void {
gpu.link(mach_builder.dependency("mach_gpu", .{ const gpu_dawn = @import("mach_gpu_dawn");
.target = step.root_module.resolved_target orelse mach_builder.host, const Options = struct {
gpu_dawn_options: gpu_dawn.Options = .{},
};
const options: Options = .{};
gpu_dawn.link(
mach_builder.dependency("mach_gpu_dawn", .{
.target = step.root_module.resolved_target.?,
.optimize = step.root_module.optimize.?, .optimize = step.root_module.optimize.?,
}).builder, step, mod, .{}) catch unreachable; }).builder,
step,
mod,
options.gpu_dawn_options,
);
step.addCSourceFile(.{ .file = .{ .path = sdkPath("/src/gpu/mach_dawn.cpp") }, .flags = &.{"-std=c++17"} });
step.addIncludePath(.{ .path = sdkPath("/src/gpu") });
} }
fn linkSysgpu(b: *std.Build, module: *std.Build.Module) void { fn linkSysgpu(b: *std.Build, module: *std.Build.Module) void {

View file

@ -27,9 +27,9 @@
.url = "https://pkg.machengine.org/mach-sysjs/eeef024f79beae189b7a4ed85e64ed076e76d538.tar.gz", .url = "https://pkg.machengine.org/mach-sysjs/eeef024f79beae189b7a4ed85e64ed076e76d538.tar.gz",
.hash = "1220db6845ce34743ae2a1ab0222efc942496adde2736c20e3443d4fde4ef64b11b9", .hash = "1220db6845ce34743ae2a1ab0222efc942496adde2736c20e3443d4fde4ef64b11b9",
}, },
.mach_gpu = .{ .mach_gpu_dawn = .{
.url = "https://pkg.machengine.org/mach-gpu/528dad0823dafeae5d474c88cc658b091bf2e605.tar.gz", .url = "https://pkg.machengine.org/mach-gpu-dawn/cce4d19945ca6102162b0cbbc546648edb38dc41.tar.gz",
.hash = "1220fe2e555ca66741539bc0f97769b2513c5e609c968d27eb8997f577a1d195f048", .hash = "1220a6e3f4772fed665bb5b1792cf5cff8ac51af42a57ad8d276e394ae19f310a92e",
}, },
.mach_glfw = .{ .mach_glfw = .{
.url = "https://pkg.machengine.org/mach-glfw/26e8af73d7d4fbdac3ff60492c44294fc0d139b7.tar.gz", .url = "https://pkg.machengine.org/mach-glfw/26e8af73d7d4fbdac3ff60492c44294fc0d139b7.tar.gz",

View file

@ -57,7 +57,7 @@ pub const options = if (@hasDecl(@import("root"), "mach_core_options"))
else else
ComptimeOptions{}; ComptimeOptions{};
pub const wgpu = @import("mach-gpu"); pub const wgpu = @import("../gpu/main.zig");
pub const gpu = if (options.use_sysgpu) sysgpu.sysgpu else wgpu; pub const gpu = if (options.use_sysgpu) sysgpu.sysgpu else wgpu;
@ -154,7 +154,9 @@ pub const Options = struct {
power_preference: gpu.PowerPreference = .undefined, power_preference: gpu.PowerPreference = .undefined,
required_features: ?[]const gpu.FeatureName = null, required_features: ?[]const gpu.FeatureName = null,
required_limits: ?gpu.Limits = null, required_limits: ?gpu.Limits = null,
swap_chain_usage: gpu.Texture.UsageFlags = .{ .render_attachment = true, }, swap_chain_usage: gpu.Texture.UsageFlags = .{
.render_attachment = true,
},
}; };
pub fn init(options_in: Options) !void { pub fn init(options_in: Options) !void {

122
src/gpu/adapter.zig Normal file
View file

@ -0,0 +1,122 @@
const std = @import("std");
const testing = std.testing;
const dawn = @import("dawn.zig");
const Bool32 = @import("main.zig").Bool32;
const ChainedStructOut = @import("main.zig").ChainedStructOut;
const Device = @import("device.zig").Device;
const Instance = @import("instance.zig").Instance;
const FeatureName = @import("main.zig").FeatureName;
const SupportedLimits = @import("main.zig").SupportedLimits;
const RequestDeviceStatus = @import("main.zig").RequestDeviceStatus;
const BackendType = @import("main.zig").BackendType;
const RequestDeviceCallback = @import("main.zig").RequestDeviceCallback;
const Impl = @import("interface.zig").Impl;
pub const Adapter = opaque {
pub const Type = enum(u32) {
discrete_gpu,
integrated_gpu,
cpu,
unknown,
pub fn name(t: Type) []const u8 {
return switch (t) {
.discrete_gpu => "Discrete GPU",
.integrated_gpu => "Integrated GPU",
.cpu => "CPU",
.unknown => "Unknown",
};
}
};
pub const Properties = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStructOut,
dawn_adapter_properties_power_preference: *const dawn.AdapterPropertiesPowerPreference,
};
next_in_chain: NextInChain = .{ .generic = null },
vendor_id: u32,
vendor_name: [*:0]const u8,
architecture: [*:0]const u8,
device_id: u32,
name: [*:0]const u8,
driver_description: [*:0]const u8,
adapter_type: Type,
backend_type: BackendType,
compatibility_mode: Bool32 = .false,
};
pub inline fn createDevice(adapter: *Adapter, descriptor: ?*const Device.Descriptor) ?*Device {
return Impl.adapterCreateDevice(adapter, descriptor);
}
/// Call once with null to determine the array length, and again to fetch the feature list.
///
/// Consider using the enumerateFeaturesOwned helper.
pub inline fn enumerateFeatures(adapter: *Adapter, features: ?[*]FeatureName) usize {
return Impl.adapterEnumerateFeatures(adapter, features);
}
/// Enumerates the adapter features, storing the result in an allocated slice which is owned by
/// the caller.
pub inline fn enumerateFeaturesOwned(adapter: *Adapter, allocator: std.mem.Allocator) ![]FeatureName {
const count = adapter.enumerateFeatures(null);
const data = try allocator.alloc(FeatureName, count);
_ = adapter.enumerateFeatures(data.ptr);
return data;
}
pub inline fn getInstance(adapter: *Adapter) *Instance {
return Impl.adapterGetInstance(adapter);
}
pub inline fn getLimits(adapter: *Adapter, limits: *SupportedLimits) bool {
return Impl.adapterGetLimits(adapter, limits) != 0;
}
pub inline fn getProperties(adapter: *Adapter, properties: *Adapter.Properties) void {
Impl.adapterGetProperties(adapter, properties);
}
pub inline fn hasFeature(adapter: *Adapter, feature: FeatureName) bool {
return Impl.adapterHasFeature(adapter, feature) != 0;
}
pub inline fn requestDevice(
adapter: *Adapter,
descriptor: ?*const Device.Descriptor,
context: anytype,
comptime callback: fn (
ctx: @TypeOf(context),
status: RequestDeviceStatus,
device: *Device,
message: ?[*:0]const u8,
) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(status: RequestDeviceStatus, device: *Device, message: ?[*:0]const u8, userdata: ?*anyopaque) callconv(.C) void {
callback(
if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))),
status,
device,
message,
);
}
};
Impl.adapterRequestDevice(adapter, descriptor, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn reference(adapter: *Adapter) void {
Impl.adapterReference(adapter);
}
pub inline fn release(adapter: *Adapter) void {
Impl.adapterRelease(adapter);
}
};
test "Adapter.Type name" {
try testing.expectEqualStrings("Discrete GPU", Adapter.Type.discrete_gpu.name());
}

88
src/gpu/bind_group.zig Normal file
View file

@ -0,0 +1,88 @@
const Buffer = @import("buffer.zig").Buffer;
const Sampler = @import("sampler.zig").Sampler;
const TextureView = @import("texture_view.zig").TextureView;
const ChainedStruct = @import("main.zig").ChainedStruct;
const BindGroupLayout = @import("bind_group_layout.zig").BindGroupLayout;
const ExternalTexture = @import("external_texture.zig").ExternalTexture;
const Impl = @import("interface.zig").Impl;
pub const BindGroup = opaque {
pub const Entry = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
external_texture_binding_entry: *const ExternalTexture.BindingEntry,
};
next_in_chain: NextInChain = .{ .generic = null },
binding: u32,
buffer: ?*Buffer = null,
offset: u64 = 0,
size: u64,
sampler: ?*Sampler = null,
texture_view: ?*TextureView = null,
/// Helper to create a buffer BindGroup.Entry.
pub fn buffer(binding: u32, buf: *Buffer, offset: u64, size: u64) Entry {
return .{
.binding = binding,
.buffer = buf,
.offset = offset,
.size = size,
};
}
/// Helper to create a sampler BindGroup.Entry.
pub fn sampler(binding: u32, _sampler: *Sampler) Entry {
return .{
.binding = binding,
.sampler = _sampler,
.size = 0,
};
}
/// Helper to create a texture view BindGroup.Entry.
pub fn textureView(binding: u32, texture_view: *TextureView) Entry {
return .{
.binding = binding,
.texture_view = texture_view,
.size = 0,
};
}
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
layout: *BindGroupLayout,
entry_count: usize = 0,
entries: ?[*]const Entry = null,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
layout: *BindGroupLayout,
entries: ?[]const Entry = null,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.layout = v.layout,
.entry_count = if (v.entries) |e| e.len else 0,
.entries = if (v.entries) |e| e.ptr else null,
};
}
};
pub inline fn setLabel(bind_group: *BindGroup, label: [*:0]const u8) void {
Impl.bindGroupSetLabel(bind_group, label);
}
pub inline fn reference(bind_group: *BindGroup) void {
Impl.bindGroupReference(bind_group);
}
pub inline fn release(bind_group: *BindGroup) void {
Impl.bindGroupRelease(bind_group);
}
};

View file

@ -0,0 +1,131 @@
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const ShaderStageFlags = @import("main.zig").ShaderStageFlags;
const Buffer = @import("buffer.zig").Buffer;
const Sampler = @import("sampler.zig").Sampler;
const Texture = @import("texture.zig").Texture;
const TextureView = @import("texture_view.zig").TextureView;
const StorageTextureBindingLayout = @import("main.zig").StorageTextureBindingLayout;
const StorageTextureAccess = @import("main.zig").StorageTextureAccess;
const ExternalTexture = @import("external_texture.zig").ExternalTexture;
const Impl = @import("interface.zig").Impl;
pub const BindGroupLayout = opaque {
pub const Entry = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
external_texture_binding_layout: *const ExternalTexture.BindingLayout,
};
next_in_chain: NextInChain = .{ .generic = null },
binding: u32,
visibility: ShaderStageFlags,
buffer: Buffer.BindingLayout = .{},
sampler: Sampler.BindingLayout = .{},
texture: Texture.BindingLayout = .{},
storage_texture: StorageTextureBindingLayout = .{},
/// Helper to create a buffer BindGroupLayout.Entry.
pub fn buffer(
binding: u32,
visibility: ShaderStageFlags,
binding_type: Buffer.BindingType,
has_dynamic_offset: bool,
min_binding_size: u64,
) Entry {
return .{
.binding = binding,
.visibility = visibility,
.buffer = .{
.type = binding_type,
.has_dynamic_offset = Bool32.from(has_dynamic_offset),
.min_binding_size = min_binding_size,
},
};
}
/// Helper to create a sampler BindGroupLayout.Entry.
pub fn sampler(
binding: u32,
visibility: ShaderStageFlags,
binding_type: Sampler.BindingType,
) Entry {
return .{
.binding = binding,
.visibility = visibility,
.sampler = .{ .type = binding_type },
};
}
/// Helper to create a texture BindGroupLayout.Entry.
pub fn texture(
binding: u32,
visibility: ShaderStageFlags,
sample_type: Texture.SampleType,
view_dimension: TextureView.Dimension,
multisampled: bool,
) Entry {
return .{
.binding = binding,
.visibility = visibility,
.texture = .{
.sample_type = sample_type,
.view_dimension = view_dimension,
.multisampled = Bool32.from(multisampled),
},
};
}
/// Helper to create a storage texture BindGroupLayout.Entry.
pub fn storageTexture(
binding: u32,
visibility: ShaderStageFlags,
access: StorageTextureAccess,
format: Texture.Format,
view_dimension: TextureView.Dimension,
) Entry {
return .{
.binding = binding,
.visibility = visibility,
.storage_texture = .{
.access = access,
.format = format,
.view_dimension = view_dimension,
},
};
}
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
entry_count: usize = 0,
entries: ?[*]const Entry = null,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
entries: ?[]const Entry = null,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.entry_count = if (v.entries) |e| e.len else 0,
.entries = if (v.entries) |e| e.ptr else null,
};
}
};
pub inline fn setLabel(bind_group_layout: *BindGroupLayout, label: [*:0]const u8) void {
Impl.bindGroupLayoutSetLabel(bind_group_layout, label);
}
pub inline fn reference(bind_group_layout: *BindGroupLayout) void {
Impl.bindGroupLayoutReference(bind_group_layout);
}
pub inline fn release(bind_group_layout: *BindGroupLayout) void {
Impl.bindGroupLayoutRelease(bind_group_layout);
}
};

166
src/gpu/buffer.zig Normal file
View file

@ -0,0 +1,166 @@
const std = @import("std");
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const dawn = @import("dawn.zig");
const MapModeFlags = @import("main.zig").MapModeFlags;
const Impl = @import("interface.zig").Impl;
pub const Buffer = opaque {
pub const MapCallback = *const fn (status: MapAsyncStatus, userdata: ?*anyopaque) callconv(.C) void;
pub const BindingType = enum(u32) {
undefined = 0x00000000,
uniform = 0x00000001,
storage = 0x00000002,
read_only_storage = 0x00000003,
};
pub const MapState = enum(u32) {
unmapped = 0x00000000,
pending = 0x00000001,
mapped = 0x00000002,
};
pub const MapAsyncStatus = enum(u32) {
success = 0x00000000,
validation_error = 0x00000001,
unknown = 0x00000002,
device_lost = 0x00000003,
destroyed_before_callback = 0x00000004,
unmapped_before_callback = 0x00000005,
mapping_already_pending = 0x00000006,
offset_out_of_range = 0x00000007,
size_out_of_range = 0x00000008,
};
pub const UsageFlags = packed struct(u32) {
map_read: bool = false,
map_write: bool = false,
copy_src: bool = false,
copy_dst: bool = false,
index: bool = false,
vertex: bool = false,
uniform: bool = false,
storage: bool = false,
indirect: bool = false,
query_resolve: bool = false,
_padding: u22 = 0,
comptime {
std.debug.assert(
@sizeOf(@This()) == @sizeOf(u32) and
@bitSizeOf(@This()) == @bitSizeOf(u32),
);
}
pub const none = UsageFlags{};
pub fn equal(a: UsageFlags, b: UsageFlags) bool {
return @as(u10, @truncate(@as(u32, @bitCast(a)))) == @as(u10, @truncate(@as(u32, @bitCast(b))));
}
};
pub const BindingLayout = extern struct {
next_in_chain: ?*const ChainedStruct = null,
type: BindingType = .undefined,
has_dynamic_offset: Bool32 = .false,
min_binding_size: u64 = 0,
};
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
dawn_buffer_descriptor_error_info_from_wire_client: *const dawn.BufferDescriptorErrorInfoFromWireClient,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
usage: UsageFlags,
size: u64,
mapped_at_creation: Bool32 = .false,
};
pub inline fn destroy(buffer: *Buffer) void {
Impl.bufferDestroy(buffer);
}
pub inline fn getMapState(buffer: *Buffer) MapState {
return Impl.bufferGetMapState(buffer);
}
/// Default `offset_bytes`: 0
/// Default `len`: `gpu.whole_map_size` / `std.math.maxint(usize)` (whole range)
pub inline fn getConstMappedRange(
buffer: *Buffer,
comptime T: type,
offset_bytes: usize,
len: usize,
) ?[]const T {
const size = @sizeOf(T) * len;
const data = Impl.bufferGetConstMappedRange(
buffer,
offset_bytes,
size + size % 4,
);
return if (data) |d| @as([*]const T, @ptrCast(@alignCast(d)))[0..len] else null;
}
/// Default `offset_bytes`: 0
/// Default `len`: `gpu.whole_map_size` / `std.math.maxint(usize)` (whole range)
pub inline fn getMappedRange(
buffer: *Buffer,
comptime T: type,
offset_bytes: usize,
len: usize,
) ?[]T {
const size = @sizeOf(T) * len;
const data = Impl.bufferGetMappedRange(
buffer,
offset_bytes,
size + size % 4,
);
return if (data) |d| @as([*]T, @ptrCast(@alignCast(d)))[0..len] else null;
}
pub inline fn getSize(buffer: *Buffer) u64 {
return Impl.bufferGetSize(buffer);
}
pub inline fn getUsage(buffer: *Buffer) Buffer.UsageFlags {
return Impl.bufferGetUsage(buffer);
}
pub inline fn mapAsync(
buffer: *Buffer,
mode: MapModeFlags,
offset: usize,
size: usize,
context: anytype,
comptime callback: fn (ctx: @TypeOf(context), status: MapAsyncStatus) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(status: MapAsyncStatus, userdata: ?*anyopaque) callconv(.C) void {
callback(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), status);
}
};
Impl.bufferMapAsync(buffer, mode, offset, size, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn setLabel(buffer: *Buffer, label: [*:0]const u8) void {
Impl.bufferSetLabel(buffer, label);
}
pub inline fn unmap(buffer: *Buffer) void {
Impl.bufferUnmap(buffer);
}
pub inline fn reference(buffer: *Buffer) void {
Impl.bufferReference(buffer);
}
pub inline fn release(buffer: *Buffer) void {
Impl.bufferRelease(buffer);
}
};

View file

@ -0,0 +1,21 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const Impl = @import("interface.zig").Impl;
pub const CommandBuffer = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
};
pub inline fn setLabel(command_buffer: *CommandBuffer, label: [*:0]const u8) void {
Impl.commandBufferSetLabel(command_buffer, label);
}
pub inline fn reference(command_buffer: *CommandBuffer) void {
Impl.commandBufferReference(command_buffer);
}
pub inline fn release(command_buffer: *CommandBuffer) void {
Impl.commandBufferRelease(command_buffer);
}
};

111
src/gpu/command_encoder.zig Normal file
View file

@ -0,0 +1,111 @@
const std = @import("std");
const ComputePassEncoder = @import("compute_pass_encoder.zig").ComputePassEncoder;
const RenderPassEncoder = @import("render_pass_encoder.zig").RenderPassEncoder;
const CommandBuffer = @import("command_buffer.zig").CommandBuffer;
const Buffer = @import("buffer.zig").Buffer;
const QuerySet = @import("query_set.zig").QuerySet;
const RenderPassDescriptor = @import("main.zig").RenderPassDescriptor;
const ComputePassDescriptor = @import("main.zig").ComputePassDescriptor;
const ChainedStruct = @import("main.zig").ChainedStruct;
const ImageCopyBuffer = @import("main.zig").ImageCopyBuffer;
const ImageCopyTexture = @import("main.zig").ImageCopyTexture;
const Extent3D = @import("main.zig").Extent3D;
const Impl = @import("interface.zig").Impl;
const dawn = @import("dawn.zig");
pub const CommandEncoder = opaque {
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
dawn_encoder_internal_usage_descriptor: *const dawn.EncoderInternalUsageDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
};
pub inline fn beginComputePass(command_encoder: *CommandEncoder, descriptor: ?*const ComputePassDescriptor) *ComputePassEncoder {
return Impl.commandEncoderBeginComputePass(command_encoder, descriptor);
}
pub inline fn beginRenderPass(command_encoder: *CommandEncoder, descriptor: *const RenderPassDescriptor) *RenderPassEncoder {
return Impl.commandEncoderBeginRenderPass(command_encoder, descriptor);
}
/// Default `offset`: 0
/// Default `size`: `gpu.whole_size`
pub inline fn clearBuffer(command_encoder: *CommandEncoder, buffer: *Buffer, offset: u64, size: u64) void {
Impl.commandEncoderClearBuffer(command_encoder, buffer, offset, size);
}
pub inline fn copyBufferToBuffer(command_encoder: *CommandEncoder, source: *Buffer, source_offset: u64, destination: *Buffer, destination_offset: u64, size: u64) void {
Impl.commandEncoderCopyBufferToBuffer(command_encoder, source, source_offset, destination, destination_offset, size);
}
pub inline fn copyBufferToTexture(command_encoder: *CommandEncoder, source: *const ImageCopyBuffer, destination: *const ImageCopyTexture, copy_size: *const Extent3D) void {
Impl.commandEncoderCopyBufferToTexture(command_encoder, source, destination, copy_size);
}
pub inline fn copyTextureToBuffer(command_encoder: *CommandEncoder, source: *const ImageCopyTexture, destination: *const ImageCopyBuffer, copy_size: *const Extent3D) void {
Impl.commandEncoderCopyTextureToBuffer(command_encoder, source, destination, copy_size);
}
pub inline fn copyTextureToTexture(command_encoder: *CommandEncoder, source: *const ImageCopyTexture, destination: *const ImageCopyTexture, copy_size: *const Extent3D) void {
Impl.commandEncoderCopyTextureToTexture(command_encoder, source, destination, copy_size);
}
pub inline fn finish(command_encoder: *CommandEncoder, descriptor: ?*const CommandBuffer.Descriptor) *CommandBuffer {
return Impl.commandEncoderFinish(command_encoder, descriptor);
}
pub inline fn injectValidationError(command_encoder: *CommandEncoder, message: [*:0]const u8) void {
Impl.commandEncoderInjectValidationError(command_encoder, message);
}
pub inline fn insertDebugMarker(command_encoder: *CommandEncoder, marker_label: [*:0]const u8) void {
Impl.commandEncoderInsertDebugMarker(command_encoder, marker_label);
}
pub inline fn popDebugGroup(command_encoder: *CommandEncoder) void {
Impl.commandEncoderPopDebugGroup(command_encoder);
}
pub inline fn pushDebugGroup(command_encoder: *CommandEncoder, group_label: [*:0]const u8) void {
Impl.commandEncoderPushDebugGroup(command_encoder, group_label);
}
pub inline fn resolveQuerySet(command_encoder: *CommandEncoder, query_set: *QuerySet, first_query: u32, query_count: u32, destination: *Buffer, destination_offset: u64) void {
Impl.commandEncoderResolveQuerySet(command_encoder, query_set, first_query, query_count, destination, destination_offset);
}
pub inline fn setLabel(command_encoder: *CommandEncoder, label: [*:0]const u8) void {
Impl.commandEncoderSetLabel(command_encoder, label);
}
pub inline fn writeBuffer(
command_encoder: *CommandEncoder,
buffer: *Buffer,
buffer_offset_bytes: u64,
data_slice: anytype,
) void {
Impl.commandEncoderWriteBuffer(
command_encoder,
buffer,
buffer_offset_bytes,
@as([*]const u8, @ptrCast(std.mem.sliceAsBytes(data_slice).ptr)),
@as(u64, @intCast(data_slice.len)) * @sizeOf(std.meta.Elem(@TypeOf(data_slice))),
);
}
pub inline fn writeTimestamp(command_encoder: *CommandEncoder, query_set: *QuerySet, query_index: u32) void {
Impl.commandEncoderWriteTimestamp(command_encoder, query_set, query_index);
}
pub inline fn reference(command_encoder: *CommandEncoder) void {
Impl.commandEncoderReference(command_encoder);
}
pub inline fn release(command_encoder: *CommandEncoder) void {
Impl.commandEncoderRelease(command_encoder);
}
};

View file

@ -0,0 +1,64 @@
const Buffer = @import("buffer.zig").Buffer;
const BindGroup = @import("bind_group.zig").BindGroup;
const ComputePipeline = @import("compute_pipeline.zig").ComputePipeline;
const QuerySet = @import("query_set.zig").QuerySet;
const Impl = @import("interface.zig").Impl;
pub const ComputePassEncoder = opaque {
/// Default `workgroup_count_y`: 1
/// Default `workgroup_count_z`: 1
pub inline fn dispatchWorkgroups(compute_pass_encoder: *ComputePassEncoder, workgroup_count_x: u32, workgroup_count_y: u32, workgroup_count_z: u32) void {
Impl.computePassEncoderDispatchWorkgroups(compute_pass_encoder, workgroup_count_x, workgroup_count_y, workgroup_count_z);
}
pub inline fn dispatchWorkgroupsIndirect(compute_pass_encoder: *ComputePassEncoder, indirect_buffer: *Buffer, indirect_offset: u64) void {
Impl.computePassEncoderDispatchWorkgroupsIndirect(compute_pass_encoder, indirect_buffer, indirect_offset);
}
pub inline fn end(compute_pass_encoder: *ComputePassEncoder) void {
Impl.computePassEncoderEnd(compute_pass_encoder);
}
pub inline fn insertDebugMarker(compute_pass_encoder: *ComputePassEncoder, marker_label: [*:0]const u8) void {
Impl.computePassEncoderInsertDebugMarker(compute_pass_encoder, marker_label);
}
pub inline fn popDebugGroup(compute_pass_encoder: *ComputePassEncoder) void {
Impl.computePassEncoderPopDebugGroup(compute_pass_encoder);
}
pub inline fn pushDebugGroup(compute_pass_encoder: *ComputePassEncoder, group_label: [*:0]const u8) void {
Impl.computePassEncoderPushDebugGroup(compute_pass_encoder, group_label);
}
/// Default `dynamic_offsets`: null
pub inline fn setBindGroup(compute_pass_encoder: *ComputePassEncoder, group_index: u32, group: *BindGroup, dynamic_offsets: ?[]const u32) void {
Impl.computePassEncoderSetBindGroup(
compute_pass_encoder,
group_index,
group,
if (dynamic_offsets) |v| v.len else 0,
if (dynamic_offsets) |v| v.ptr else null,
);
}
pub inline fn setLabel(compute_pass_encoder: *ComputePassEncoder, label: [*:0]const u8) void {
Impl.computePassEncoderSetLabel(compute_pass_encoder, label);
}
pub inline fn setPipeline(compute_pass_encoder: *ComputePassEncoder, pipeline: *ComputePipeline) void {
Impl.computePassEncoderSetPipeline(compute_pass_encoder, pipeline);
}
pub inline fn writeTimestamp(compute_pass_encoder: *ComputePassEncoder, query_set: *QuerySet, query_index: u32) void {
Impl.computePassEncoderWriteTimestamp(compute_pass_encoder, query_set, query_index);
}
pub inline fn reference(compute_pass_encoder: *ComputePassEncoder) void {
Impl.computePassEncoderReference(compute_pass_encoder);
}
pub inline fn release(compute_pass_encoder: *ComputePassEncoder) void {
Impl.computePassEncoderRelease(compute_pass_encoder);
}
};

View file

@ -0,0 +1,30 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const ProgrammableStageDescriptor = @import("main.zig").ProgrammableStageDescriptor;
const PipelineLayout = @import("pipeline_layout.zig").PipelineLayout;
const BindGroupLayout = @import("bind_group_layout.zig").BindGroupLayout;
const Impl = @import("interface.zig").Impl;
pub const ComputePipeline = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
layout: ?*PipelineLayout = null,
compute: ProgrammableStageDescriptor,
};
pub inline fn getBindGroupLayout(compute_pipeline: *ComputePipeline, group_index: u32) *BindGroupLayout {
return Impl.computePipelineGetBindGroupLayout(compute_pipeline, group_index);
}
pub inline fn setLabel(compute_pipeline: *ComputePipeline, label: [*:0]const u8) void {
Impl.computePipelineSetLabel(compute_pipeline, label);
}
pub inline fn reference(compute_pipeline: *ComputePipeline) void {
Impl.computePipelineReference(compute_pipeline);
}
pub inline fn release(compute_pipeline: *ComputePipeline) void {
Impl.computePipelineRelease(compute_pipeline);
}
};

75
src/gpu/dawn.zig Normal file
View file

@ -0,0 +1,75 @@
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const ChainedStructOut = @import("main.zig").ChainedStructOut;
const PowerPreference = @import("main.zig").PowerPreference;
const Texture = @import("texture.zig").Texture;
pub const Interface = @import("dawn_impl.zig").Interface;
pub const CacheDeviceDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_cache_device_descriptor },
isolation_key: [*:0]const u8 = "",
};
pub const EncoderInternalUsageDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_encoder_internal_usage_descriptor },
use_internal_usages: Bool32 = .false,
};
pub const MultisampleStateRenderToSingleSampled = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_multisample_state_render_to_single_sampled },
enabled: Bool32 = .false,
};
pub const RenderPassColorAttachmentRenderToSingleSampled = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_render_pass_color_attachment_render_to_single_sampled },
implicit_sample_count: u32 = 1,
};
pub const TextureInternalUsageDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_texture_internal_usage_descriptor },
internal_usage: Texture.UsageFlags = Texture.UsageFlags.none,
};
pub const TogglesDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_toggles_descriptor },
enabled_toggles_count: usize = 0,
enabled_toggles: ?[*]const [*:0]const u8 = null,
disabled_toggles_count: usize = 0,
disabled_toggles: ?[*]const [*:0]const u8 = null,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_toggles_descriptor },
enabled_toggles: ?[]const [*:0]const u8 = null,
disabled_toggles: ?[]const [*:0]const u8 = null,
}) TogglesDescriptor {
return .{
.chain = v.chain,
.enabled_toggles_count = if (v.enabled_toggles) |e| e.len else 0,
.enabled_toggles = if (v.enabled_toggles) |e| e.ptr else null,
.disabled_toggles_count = if (v.disabled_toggles) |e| e.len else 0,
.disabled_toggles = if (v.disabled_toggles) |e| e.ptr else null,
};
}
};
pub const ShaderModuleSPIRVOptionsDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .dawn_shader_module_spirv_options_descriptor },
allow_non_uniform_derivatives: Bool32 = .false,
};
pub const AdapterPropertiesPowerPreference = extern struct {
chain: ChainedStructOut = .{
.next = null,
.s_type = .dawn_adapter_properties_power_preference,
},
power_preference: PowerPreference = .undefined,
};
pub const BufferDescriptorErrorInfoFromWireClient = extern struct {
chain: ChainedStruct = .{
.next = null,
.s_type = .dawn_buffer_descriptor_error_info_from_wire_client,
},
out_of_memory: Bool32 = .false,
};

1270
src/gpu/dawn_impl.zig Normal file

File diff suppressed because it is too large Load diff

368
src/gpu/device.zig Normal file
View file

@ -0,0 +1,368 @@
const std = @import("std");
const Adapter = @import("adapter.zig").Adapter;
const Queue = @import("queue.zig").Queue;
const BindGroup = @import("bind_group.zig").BindGroup;
const BindGroupLayout = @import("bind_group_layout.zig").BindGroupLayout;
const Buffer = @import("buffer.zig").Buffer;
const CommandEncoder = @import("command_encoder.zig").CommandEncoder;
const ComputePipeline = @import("compute_pipeline.zig").ComputePipeline;
const ExternalTexture = @import("external_texture.zig").ExternalTexture;
const PipelineLayout = @import("pipeline_layout.zig").PipelineLayout;
const QuerySet = @import("query_set.zig").QuerySet;
const RenderBundleEncoder = @import("render_bundle_encoder.zig").RenderBundleEncoder;
const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
const Sampler = @import("sampler.zig").Sampler;
const ShaderModule = @import("shader_module.zig").ShaderModule;
const Surface = @import("surface.zig").Surface;
const SwapChain = @import("swap_chain.zig").SwapChain;
const Texture = @import("texture.zig").Texture;
const ChainedStruct = @import("main.zig").ChainedStruct;
const FeatureName = @import("main.zig").FeatureName;
const RequiredLimits = @import("main.zig").RequiredLimits;
const SupportedLimits = @import("main.zig").SupportedLimits;
const ErrorType = @import("main.zig").ErrorType;
const ErrorFilter = @import("main.zig").ErrorFilter;
const LoggingType = @import("main.zig").LoggingType;
const CreatePipelineAsyncStatus = @import("main.zig").CreatePipelineAsyncStatus;
const LoggingCallback = @import("main.zig").LoggingCallback;
const ErrorCallback = @import("main.zig").ErrorCallback;
const CreateComputePipelineAsyncCallback = @import("main.zig").CreateComputePipelineAsyncCallback;
const CreateRenderPipelineAsyncCallback = @import("main.zig").CreateRenderPipelineAsyncCallback;
const Impl = @import("interface.zig").Impl;
const dawn = @import("dawn.zig");
pub const Device = opaque {
pub const LostCallback = *const fn (
reason: LostReason,
message: [*:0]const u8,
userdata: ?*anyopaque,
) callconv(.C) void;
pub const LostReason = enum(u32) {
undefined = 0x00000000,
destroyed = 0x00000001,
};
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
dawn_toggles_descriptor: *const dawn.TogglesDescriptor,
dawn_cache_device_descriptor: *const dawn.CacheDeviceDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
required_features_count: usize = 0,
required_features: ?[*]const FeatureName = null,
required_limits: ?*const RequiredLimits = null,
default_queue: Queue.Descriptor = Queue.Descriptor{},
device_lost_callback: LostCallback,
device_lost_userdata: ?*anyopaque,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
required_features: ?[]const FeatureName = null,
required_limits: ?*const RequiredLimits = null,
default_queue: Queue.Descriptor = Queue.Descriptor{},
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.required_features_count = if (v.required_features) |e| e.len else 0,
.required_features = if (v.required_features) |e| e.ptr else null,
.default_queue = v.default_queue,
};
}
};
pub inline fn createBindGroup(device: *Device, descriptor: *const BindGroup.Descriptor) *BindGroup {
return Impl.deviceCreateBindGroup(device, descriptor);
}
pub inline fn createBindGroupLayout(device: *Device, descriptor: *const BindGroupLayout.Descriptor) *BindGroupLayout {
return Impl.deviceCreateBindGroupLayout(device, descriptor);
}
pub inline fn createBuffer(device: *Device, descriptor: *const Buffer.Descriptor) *Buffer {
return Impl.deviceCreateBuffer(device, descriptor);
}
pub inline fn createCommandEncoder(device: *Device, descriptor: ?*const CommandEncoder.Descriptor) *CommandEncoder {
return Impl.deviceCreateCommandEncoder(device, descriptor);
}
pub inline fn createComputePipeline(device: *Device, descriptor: *const ComputePipeline.Descriptor) *ComputePipeline {
return Impl.deviceCreateComputePipeline(device, descriptor);
}
pub inline fn createComputePipelineAsync(
device: *Device,
descriptor: *const ComputePipeline.Descriptor,
context: anytype,
comptime callback: fn (
status: CreatePipelineAsyncStatus,
compute_pipeline: ?*ComputePipeline,
message: ?[*:0]const u8,
ctx: @TypeOf(context),
) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(
status: CreatePipelineAsyncStatus,
compute_pipeline: ?*ComputePipeline,
message: ?[*:0]const u8,
userdata: ?*anyopaque,
) callconv(.C) void {
callback(
status,
compute_pipeline,
message,
if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))),
);
}
};
Impl.deviceCreateComputePipelineAsync(device, descriptor, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn createErrorBuffer(device: *Device, descriptor: *const Buffer.Descriptor) *Buffer {
return Impl.deviceCreateErrorBuffer(device, descriptor);
}
pub inline fn createErrorExternalTexture(device: *Device) *ExternalTexture {
return Impl.deviceCreateErrorExternalTexture(device);
}
pub inline fn createErrorTexture(device: *Device, descriptor: *const Texture.Descriptor) *Texture {
return Impl.deviceCreateErrorTexture(device, descriptor);
}
pub inline fn createExternalTexture(device: *Device, external_texture_descriptor: *const ExternalTexture.Descriptor) *ExternalTexture {
return Impl.deviceCreateExternalTexture(device, external_texture_descriptor);
}
pub inline fn createPipelineLayout(device: *Device, pipeline_layout_descriptor: *const PipelineLayout.Descriptor) *PipelineLayout {
return Impl.deviceCreatePipelineLayout(device, pipeline_layout_descriptor);
}
pub inline fn createQuerySet(device: *Device, descriptor: *const QuerySet.Descriptor) *QuerySet {
return Impl.deviceCreateQuerySet(device, descriptor);
}
pub inline fn createRenderBundleEncoder(device: *Device, descriptor: *const RenderBundleEncoder.Descriptor) *RenderBundleEncoder {
return Impl.deviceCreateRenderBundleEncoder(device, descriptor);
}
pub inline fn createRenderPipeline(device: *Device, descriptor: *const RenderPipeline.Descriptor) *RenderPipeline {
return Impl.deviceCreateRenderPipeline(device, descriptor);
}
pub inline fn createRenderPipelineAsync(
device: *Device,
descriptor: *const RenderPipeline.Descriptor,
context: anytype,
comptime callback: fn (
ctx: @TypeOf(context),
status: CreatePipelineAsyncStatus,
pipeline: ?*RenderPipeline,
message: ?[*:0]const u8,
) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(
status: CreatePipelineAsyncStatus,
pipeline: ?*RenderPipeline,
message: ?[*:0]const u8,
userdata: ?*anyopaque,
) callconv(.C) void {
callback(
if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))),
status,
pipeline,
message,
);
}
};
Impl.deviceCreateRenderPipelineAsync(device, descriptor, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn createSampler(device: *Device, descriptor: ?*const Sampler.Descriptor) *Sampler {
return Impl.deviceCreateSampler(device, descriptor);
}
pub inline fn createShaderModule(device: *Device, descriptor: *const ShaderModule.Descriptor) *ShaderModule {
return Impl.deviceCreateShaderModule(device, descriptor);
}
/// Helper to make createShaderModule invocations slightly nicer.
pub inline fn createShaderModuleWGSL(
device: *Device,
label: ?[*:0]const u8,
wgsl_code: [*:0]const u8,
) *ShaderModule {
return device.createShaderModule(&ShaderModule.Descriptor{
.next_in_chain = .{ .wgsl_descriptor = &.{
.code = wgsl_code,
} },
.label = label,
});
}
pub inline fn createSwapChain(device: *Device, surface: ?*Surface, descriptor: *const SwapChain.Descriptor) *SwapChain {
return Impl.deviceCreateSwapChain(device, surface, descriptor);
}
pub inline fn createTexture(device: *Device, descriptor: *const Texture.Descriptor) *Texture {
return Impl.deviceCreateTexture(device, descriptor);
}
pub inline fn destroy(device: *Device) void {
Impl.deviceDestroy(device);
}
/// Call once with null to determine the array length, and again to fetch the feature list.
///
/// Consider using the enumerateFeaturesOwned helper.
pub inline fn enumerateFeatures(device: *Device, features: ?[*]FeatureName) usize {
return Impl.deviceEnumerateFeatures(device, features);
}
/// Enumerates the adapter features, storing the result in an allocated slice which is owned by
/// the caller.
pub inline fn enumerateFeaturesOwned(device: *Device, allocator: std.mem.Allocator) ![]FeatureName {
const count = device.enumerateFeatures(null);
const data = try allocator.alloc(FeatureName, count);
_ = device.enumerateFeatures(data.ptr);
return data;
}
pub inline fn forceLoss(device: *Device, reason: LostReason, message: [*:0]const u8) void {
return Impl.deviceForceLoss(device, reason, message);
}
pub inline fn getAdapter(device: *Device) *Adapter {
return Impl.deviceGetAdapter(device);
}
pub inline fn getLimits(device: *Device, limits: *SupportedLimits) bool {
return Impl.deviceGetLimits(device, limits) != 0;
}
pub inline fn getQueue(device: *Device) *Queue {
return Impl.deviceGetQueue(device);
}
pub inline fn hasFeature(device: *Device, feature: FeatureName) bool {
return Impl.deviceHasFeature(device, feature) != 0;
}
pub inline fn injectError(device: *Device, typ: ErrorType, message: [*:0]const u8) void {
Impl.deviceInjectError(device, typ, message);
}
pub inline fn popErrorScope(
device: *Device,
context: anytype,
comptime callback: fn (ctx: @TypeOf(context), typ: ErrorType, message: [*:0]const u8) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(typ: ErrorType, message: [*:0]const u8, userdata: ?*anyopaque) callconv(.C) void {
callback(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), typ, message);
}
};
Impl.devicePopErrorScope(device, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn pushErrorScope(device: *Device, filter: ErrorFilter) void {
Impl.devicePushErrorScope(device, filter);
}
pub inline fn setDeviceLostCallback(
device: *Device,
context: anytype,
comptime callback: ?fn (ctx: @TypeOf(context), reason: LostReason, message: [*:0]const u8) callconv(.Inline) void,
) void {
if (callback) |cb| {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(reason: LostReason, message: [*:0]const u8, userdata: ?*anyopaque) callconv(.C) void {
cb(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), reason, message);
}
};
Impl.deviceSetDeviceLostCallback(device, Helper.cCallback, if (Context == void) null else context);
} else {
Impl.deviceSetDeviceLostCallback(device, null, null);
}
}
pub inline fn setLabel(device: *Device, label: [*:0]const u8) void {
Impl.deviceSetLabel(device, label);
}
pub inline fn setLoggingCallback(
device: *Device,
context: anytype,
comptime callback: ?fn (ctx: @TypeOf(context), typ: LoggingType, message: [*:0]const u8) callconv(.Inline) void,
) void {
if (callback) |cb| {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(typ: LoggingType, message: [*:0]const u8, userdata: ?*anyopaque) callconv(.C) void {
cb(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), typ, message);
}
};
Impl.deviceSetLoggingCallback(device, Helper.cCallback, if (Context == void) null else context);
} else {
Impl.deviceSetLoggingCallback(device, null, null);
}
}
pub inline fn setUncapturedErrorCallback(
device: *Device,
context: anytype,
comptime callback: ?fn (ctx: @TypeOf(context), typ: ErrorType, message: [*:0]const u8) callconv(.Inline) void,
) void {
if (callback) |cb| {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(typ: ErrorType, message: [*:0]const u8, userdata: ?*anyopaque) callconv(.C) void {
cb(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), typ, message);
}
};
Impl.deviceSetUncapturedErrorCallback(device, Helper.cCallback, if (Context == void) null else context);
} else {
Impl.deviceSetUncapturedErrorCallback(device, null, null);
}
}
pub inline fn tick(device: *Device) void {
Impl.deviceTick(device);
}
// Mach WebGPU extension. Supported with mach-gpu-dawn.
//
// When making Metal interop with other APIs, we need to be careful that QueueSubmit doesn't
// mean that the operations will be visible to other APIs/Metal devices right away. macOS
// does have a global queue of graphics operations, but the command buffers are inserted there
// when they are "scheduled". Submitting other operations before the command buffer is
// scheduled could lead to races in who gets scheduled first and incorrect rendering.
pub inline fn machWaitForCommandsToBeScheduled(device: *Device) void {
Impl.machDeviceWaitForCommandsToBeScheduled(device);
}
pub inline fn validateTextureDescriptor(device: *Device, descriptor: *const Texture.Descriptor) void {
Impl.deviceVlidateTextureDescriptor(device, descriptor);
}
pub inline fn reference(device: *Device) void {
Impl.deviceReference(device);
}
pub inline fn release(device: *Device) void {
Impl.deviceRelease(device);
}
};

245
src/gpu/example/main.zig Normal file
View file

@ -0,0 +1,245 @@
const std = @import("std");
const util = @import("util.zig");
const glfw = @import("mach-glfw");
const gpu = @import("mach").gpu;
pub const GPUInterface = gpu.dawn.Interface;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var allocator = gpa.allocator();
try gpu.Impl.init(allocator, .{});
const setup = try setupWindow(allocator);
const framebuffer_size = setup.window.getFramebufferSize();
const window_data = try allocator.create(WindowData);
window_data.* = .{
.surface = setup.surface,
.swap_chain = null,
.swap_chain_format = undefined,
.current_desc = undefined,
.target_desc = undefined,
};
setup.window.setUserPointer(window_data);
window_data.swap_chain_format = .bgra8_unorm;
const descriptor = gpu.SwapChain.Descriptor{
.label = "basic swap chain",
.usage = .{ .render_attachment = true },
.format = window_data.swap_chain_format,
.width = framebuffer_size.width,
.height = framebuffer_size.height,
.present_mode = .fifo,
};
window_data.current_desc = descriptor;
window_data.target_desc = descriptor;
const vs =
\\ @vertex fn main(
\\ @builtin(vertex_index) VertexIndex : u32
\\ ) -> @builtin(position) vec4<f32> {
\\ var pos = array<vec2<f32>, 3>(
\\ vec2<f32>( 0.0, 0.5),
\\ vec2<f32>(-0.5, -0.5),
\\ vec2<f32>( 0.5, -0.5)
\\ );
\\ return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
\\ }
;
const vs_module = setup.device.createShaderModuleWGSL("my vertex shader", vs);
const fs =
\\ @fragment fn main() -> @location(0) vec4<f32> {
\\ return vec4<f32>(1.0, 0.0, 0.0, 1.0);
\\ }
;
const fs_module = setup.device.createShaderModuleWGSL("my fragment shader", fs);
// Fragment state
const blend = gpu.BlendState{
.color = .{
.dst_factor = .one,
},
.alpha = .{
.dst_factor = .one,
},
};
const color_target = gpu.ColorTargetState{
.format = window_data.swap_chain_format,
.blend = &blend,
.write_mask = gpu.ColorWriteMaskFlags.all,
};
const fragment = gpu.FragmentState.init(.{
.module = fs_module,
.entry_point = "main",
.targets = &.{color_target},
});
const pipeline_descriptor = gpu.RenderPipeline.Descriptor{
.fragment = &fragment,
.layout = null,
.depth_stencil = null,
.vertex = gpu.VertexState{
.module = vs_module,
.entry_point = "main",
},
.multisample = .{},
.primitive = .{},
};
const pipeline = setup.device.createRenderPipeline(&pipeline_descriptor);
vs_module.release();
fs_module.release();
// Reconfigure the swap chain with the new framebuffer width/height, otherwise e.g. the Vulkan
// device would be lost after a resize.
setup.window.setFramebufferSizeCallback((struct {
fn callback(window: glfw.Window, width: u32, height: u32) void {
const pl = window.getUserPointer(WindowData);
pl.?.target_desc.width = width;
pl.?.target_desc.height = height;
}
}).callback);
const queue = setup.device.getQueue();
while (!setup.window.shouldClose()) {
try frame(.{
.window = setup.window,
.device = setup.device,
.pipeline = pipeline,
.queue = queue,
});
std.time.sleep(16 * std.time.ns_per_ms);
}
}
const WindowData = struct {
surface: ?*gpu.Surface,
swap_chain: ?*gpu.SwapChain,
swap_chain_format: gpu.Texture.Format,
current_desc: gpu.SwapChain.Descriptor,
target_desc: gpu.SwapChain.Descriptor,
};
const FrameParams = struct {
window: glfw.Window,
device: *gpu.Device,
pipeline: *gpu.RenderPipeline,
queue: *gpu.Queue,
};
fn frame(params: FrameParams) !void {
glfw.pollEvents();
params.device.tick();
const pl = params.window.getUserPointer(WindowData).?;
if (pl.swap_chain == null or !std.meta.eql(pl.current_desc, pl.target_desc)) {
pl.swap_chain = params.device.createSwapChain(pl.surface, &pl.target_desc);
pl.current_desc = pl.target_desc;
}
const back_buffer_view = pl.swap_chain.?.getCurrentTextureView().?;
const color_attachment = gpu.RenderPassColorAttachment{
.view = back_buffer_view,
.resolve_target = null,
.clear_value = std.mem.zeroes(gpu.Color),
.load_op = .clear,
.store_op = .store,
};
const encoder = params.device.createCommandEncoder(null);
const render_pass_info = gpu.RenderPassDescriptor.init(.{
.color_attachments = &.{color_attachment},
});
const pass = encoder.beginRenderPass(&render_pass_info);
pass.setPipeline(params.pipeline);
pass.draw(3, 1, 0, 0);
pass.end();
pass.release();
var command = encoder.finish(null);
encoder.release();
params.queue.submit(&[_]*gpu.CommandBuffer{command});
command.release();
pl.swap_chain.?.present();
back_buffer_view.release();
}
const Setup = struct {
instance: *gpu.Instance,
adapter: *gpu.Adapter,
device: *gpu.Device,
window: glfw.Window,
surface: *gpu.Surface,
};
/// Default GLFW error handling callback
fn errorCallback(error_code: glfw.ErrorCode, description: [:0]const u8) void {
std.log.err("glfw: {}: {s}\n", .{ error_code, description });
}
pub fn setupWindow(allocator: std.mem.Allocator) !Setup {
const backend_type = try util.detectBackendType(allocator);
glfw.setErrorCallback(errorCallback);
if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
}
// Create the test window and discover adapters using it (esp. for OpenGL)
var hints = util.glfwWindowHintsForBackend(backend_type);
hints.cocoa_retina_framebuffer = true;
const window = glfw.Window.create(640, 480, "mach/gpu window", null, null, hints) orelse {
std.log.err("failed to create GLFW window: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
};
if (backend_type == .opengl) glfw.makeContextCurrent(window);
if (backend_type == .opengles) glfw.makeContextCurrent(window);
const instance = gpu.createInstance(null);
if (instance == null) {
std.debug.print("failed to create GPU instance\n", .{});
std.process.exit(1);
}
const surface = try util.createSurfaceForWindow(instance.?, window, comptime util.detectGLFWOptions());
var response: util.RequestAdapterResponse = undefined;
instance.?.requestAdapter(&gpu.RequestAdapterOptions{
.compatible_surface = surface,
.power_preference = .undefined,
.force_fallback_adapter = .false,
}, &response, util.requestAdapterCallback);
if (response.status != .success) {
std.debug.print("failed to create GPU adapter: {s}\n", .{response.message.?});
std.process.exit(1);
}
// Print which adapter we are using.
var props = std.mem.zeroes(gpu.Adapter.Properties);
response.adapter.?.getProperties(&props);
std.debug.print("found {s} backend on {s} adapter: {s}, {s}\n", .{
props.backend_type.name(),
props.adapter_type.name(),
props.name,
props.driver_description,
});
// Create a device with default limits/features.
const device = response.adapter.?.createDevice(null);
if (device == null) {
std.debug.print("failed to create GPU device\n", .{});
std.process.exit(1);
}
device.?.setUncapturedErrorCallback({}, util.printUnhandledErrorCallback);
return Setup{
.instance = instance.?,
.adapter = response.adapter.?,
.device = device.?,
.window = window,
.surface = surface,
};
}

View file

@ -0,0 +1,7 @@
// Extracted from `zig translate-c tmp.c` with `#include <objc/message.h>` in the file.
pub const SEL = opaque {};
pub const Class = opaque {};
pub extern fn sel_getUid(str: [*c]const u8) ?*SEL;
pub extern fn objc_getClass(name: [*c]const u8) ?*Class;
pub extern fn objc_msgSend() void;

201
src/gpu/example/util.zig Normal file
View file

@ -0,0 +1,201 @@
const std = @import("std");
const glfw = @import("mach-glfw");
const gpu = @import("mach").gpu;
const objc = @import("objc_message.zig");
pub inline fn printUnhandledErrorCallback(_: void, typ: gpu.ErrorType, message: [*:0]const u8) void {
switch (typ) {
.validation => std.log.err("gpu: validation error: {s}\n", .{message}),
.out_of_memory => std.log.err("gpu: out of memory: {s}\n", .{message}),
.device_lost => std.log.err("gpu: device lost: {s}\n", .{message}),
.unknown => std.log.err("gpu: unknown error: {s}\n", .{message}),
else => unreachable,
}
std.os.exit(1);
}
fn getEnvVarOwned(allocator: std.mem.Allocator, key: []const u8) error{ OutOfMemory, InvalidUtf8, InvalidWtf8 }!?[]u8 {
return std.process.getEnvVarOwned(allocator, key) catch |err| switch (err) {
error.EnvironmentVariableNotFound => @as(?[]u8, null),
else => |e| e,
};
}
pub fn detectBackendType(allocator: std.mem.Allocator) !gpu.BackendType {
const MACH_GPU_BACKEND = try getEnvVarOwned(allocator, "MACH_GPU_BACKEND");
if (MACH_GPU_BACKEND) |backend| {
defer allocator.free(backend);
if (std.ascii.eqlIgnoreCase(backend, "null")) return .null;
if (std.ascii.eqlIgnoreCase(backend, "d3d11")) return .d3d11;
if (std.ascii.eqlIgnoreCase(backend, "d3d12")) return .d3d12;
if (std.ascii.eqlIgnoreCase(backend, "metal")) return .metal;
if (std.ascii.eqlIgnoreCase(backend, "vulkan")) return .vulkan;
if (std.ascii.eqlIgnoreCase(backend, "opengl")) return .opengl;
if (std.ascii.eqlIgnoreCase(backend, "opengles")) return .opengles;
@panic("unknown MACH_GPU_BACKEND type");
}
const target = @import("builtin").target;
if (target.isDarwin()) return .metal;
if (target.os.tag == .windows) return .d3d12;
return .vulkan;
}
pub const RequestAdapterResponse = struct {
status: gpu.RequestAdapterStatus,
adapter: ?*gpu.Adapter,
message: ?[*:0]const u8,
};
pub inline fn requestAdapterCallback(
context: *RequestAdapterResponse,
status: gpu.RequestAdapterStatus,
adapter: ?*gpu.Adapter,
message: ?[*:0]const u8,
) void {
context.* = RequestAdapterResponse{
.status = status,
.adapter = adapter,
.message = message,
};
}
pub fn glfwWindowHintsForBackend(backend: gpu.BackendType) glfw.Window.Hints {
return switch (backend) {
.opengl => .{
// Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and
// texture views.
.context_version_major = 4,
.context_version_minor = 4,
.opengl_forward_compat = true,
.opengl_profile = .opengl_core_profile,
},
.opengles => .{
.context_version_major = 3,
.context_version_minor = 1,
.client_api = .opengl_es_api,
.context_creation_api = .egl_context_api,
},
else => .{
// Without this GLFW will initialize a GL context on the window, which prevents using
// the window with other APIs (by crashing in weird ways).
.client_api = .no_api,
},
};
}
pub fn detectGLFWOptions() glfw.BackendOptions {
const target = @import("builtin").target;
if (target.isDarwin()) return .{ .cocoa = true };
return switch (target.os.tag) {
.windows => .{ .win32 = true },
.linux => .{ .x11 = true, .wayland = true },
else => .{},
};
}
pub fn createSurfaceForWindow(
instance: *gpu.Instance,
window: glfw.Window,
comptime glfw_options: glfw.BackendOptions,
) !*gpu.Surface {
const glfw_native = glfw.Native(glfw_options);
if (glfw_options.win32) {
return instance.createSurface(&gpu.Surface.Descriptor{
.next_in_chain = .{
.from_windows_hwnd = &.{
.hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
.hwnd = glfw_native.getWin32Window(window),
},
},
});
} else if (glfw_options.x11) {
return instance.createSurface(&gpu.Surface.Descriptor{
.next_in_chain = .{
.from_xlib_window = &.{
.display = glfw_native.getX11Display(),
.window = glfw_native.getX11Window(window),
},
},
});
} else if (glfw_options.wayland) {
return instance.createSurface(&gpu.Surface.Descriptor{
.next_in_chain = .{
.from_wayland_surface = &.{
.display = glfw_native.getWaylandDisplay(),
.surface = glfw_native.getWaylandWindow(window),
},
},
});
} else if (glfw_options.cocoa) {
const pool = try AutoReleasePool.init();
defer AutoReleasePool.release(pool);
const ns_window = glfw_native.getCocoaWindow(window);
const ns_view = msgSend(ns_window, "contentView", .{}, *anyopaque); // [nsWindow contentView]
// Create a CAMetalLayer that covers the whole window that will be passed to CreateSurface.
msgSend(ns_view, "setWantsLayer:", .{true}, void); // [view setWantsLayer:YES]
const layer = msgSend(objc.objc_getClass("CAMetalLayer"), "layer", .{}, ?*anyopaque); // [CAMetalLayer layer]
if (layer == null) @panic("failed to create Metal layer");
msgSend(ns_view, "setLayer:", .{layer.?}, void); // [view setLayer:layer]
// Use retina if the window was created with retina support.
const scale_factor = msgSend(ns_window, "backingScaleFactor", .{}, f64); // [ns_window backingScaleFactor]
msgSend(layer.?, "setContentsScale:", .{scale_factor}, void); // [layer setContentsScale:scale_factor]
return instance.createSurface(&gpu.Surface.Descriptor{
.next_in_chain = .{
.from_metal_layer = &.{ .layer = layer.? },
},
});
} else unreachable;
}
pub const AutoReleasePool = if (!@import("builtin").target.isDarwin()) opaque {
pub fn init() error{OutOfMemory}!?*AutoReleasePool {
return null;
}
pub fn release(pool: ?*AutoReleasePool) void {
_ = pool;
return;
}
} else opaque {
pub fn init() error{OutOfMemory}!?*AutoReleasePool {
// pool = [NSAutoreleasePool alloc];
var pool = msgSend(objc.objc_getClass("NSAutoreleasePool"), "alloc", .{}, ?*AutoReleasePool);
if (pool == null) return error.OutOfMemory;
// pool = [pool init];
pool = msgSend(pool, "init", .{}, ?*AutoReleasePool);
if (pool == null) unreachable;
return pool;
}
pub fn release(pool: ?*AutoReleasePool) void {
// [pool release];
msgSend(pool, "release", .{}, void);
}
};
// Borrowed from https://github.com/hazeycode/zig-objcrt
pub fn msgSend(obj: anytype, sel_name: [:0]const u8, args: anytype, comptime ReturnType: type) ReturnType {
const args_meta = @typeInfo(@TypeOf(args)).Struct.fields;
const FnType = switch (args_meta.len) {
0 => *const fn (@TypeOf(obj), ?*objc.SEL) callconv(.C) ReturnType,
1 => *const fn (@TypeOf(obj), ?*objc.SEL, args_meta[0].type) callconv(.C) ReturnType,
2 => *const fn (@TypeOf(obj), ?*objc.SEL, args_meta[0].type, args_meta[1].type) callconv(.C) ReturnType,
3 => *const fn (@TypeOf(obj), ?*objc.SEL, args_meta[0].type, args_meta[1].type, args_meta[2].type) callconv(.C) ReturnType,
4 => *const fn (@TypeOf(obj), ?*objc.SEL, args_meta[0].type, args_meta[1].type, args_meta[2].type, args_meta[3].type) callconv(.C) ReturnType,
else => @compileError("Unsupported number of args"),
};
const func = @as(FnType, @ptrCast(&objc.objc_msgSend));
const sel = objc.sel_getUid(@as([*c]const u8, @ptrCast(sel_name)));
return @call(.auto, func, .{ obj, sel } ++ args);
}

View file

@ -0,0 +1,56 @@
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const TextureView = @import("texture_view.zig").TextureView;
const Origin2D = @import("main.zig").Origin2D;
const Extent2D = @import("main.zig").Extent2D;
const Impl = @import("interface.zig").Impl;
pub const ExternalTexture = opaque {
pub const BindingEntry = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .external_texture_binding_entry },
external_texture: *ExternalTexture,
};
pub const BindingLayout = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .external_texture_binding_layout },
};
const Rotation = enum(u32) {
rotate_0_degrees = 0x00000000,
rotate_90_degrees = 0x00000001,
rotate_180_degrees = 0x00000002,
rotate_270_degrees = 0x00000003,
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
plane0: *TextureView,
plane1: ?*TextureView = null,
visible_origin: Origin2D,
visible_size: Extent2D,
do_yuv_to_rgb_conversion_only: Bool32 = .false,
yuv_to_rgb_conversion_matrix: ?*const [12]f32 = null,
src_transform_function_parameters: *const [7]f32,
dst_transform_function_parameters: *const [7]f32,
gamut_conversion_matrix: *const [9]f32,
flip_y: Bool32,
rotation: Rotation,
};
pub inline fn destroy(external_texture: *ExternalTexture) void {
Impl.externalTextureDestroy(external_texture);
}
pub inline fn setLabel(external_texture: *ExternalTexture, label: [*:0]const u8) void {
Impl.externalTextureSetLabel(external_texture, label);
}
pub inline fn reference(external_texture: *ExternalTexture) void {
Impl.externalTextureReference(external_texture);
}
pub inline fn release(external_texture: *ExternalTexture) void {
Impl.externalTextureRelease(external_texture);
}
};

65
src/gpu/instance.zig Normal file
View file

@ -0,0 +1,65 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const RequestAdapterStatus = @import("main.zig").RequestAdapterStatus;
const Surface = @import("surface.zig").Surface;
const Adapter = @import("adapter.zig").Adapter;
const RequestAdapterOptions = @import("main.zig").RequestAdapterOptions;
const RequestAdapterCallback = @import("main.zig").RequestAdapterCallback;
const Impl = @import("interface.zig").Impl;
const dawn = @import("dawn.zig");
pub const Instance = opaque {
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
dawn_toggles_descriptor: *const dawn.TogglesDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
};
pub inline fn createSurface(instance: *Instance, descriptor: *const Surface.Descriptor) *Surface {
return Impl.instanceCreateSurface(instance, descriptor);
}
pub inline fn processEvents(instance: *Instance) void {
Impl.instanceProcessEvents(instance);
}
pub inline fn requestAdapter(
instance: *Instance,
options: ?*const RequestAdapterOptions,
context: anytype,
comptime callback: fn (
ctx: @TypeOf(context),
status: RequestAdapterStatus,
adapter: ?*Adapter,
message: ?[*:0]const u8,
) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(
status: RequestAdapterStatus,
adapter: ?*Adapter,
message: ?[*:0]const u8,
userdata: ?*anyopaque,
) callconv(.C) void {
callback(
if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))),
status,
adapter,
message,
);
}
};
Impl.instanceRequestAdapter(instance, options, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn reference(instance: *Instance) void {
Impl.instanceReference(instance);
}
pub inline fn release(instance: *Instance) void {
Impl.instanceRelease(instance);
}
};

2702
src/gpu/interface.zig Normal file

File diff suppressed because it is too large Load diff

28
src/gpu/mach_dawn.cpp Normal file
View file

@ -0,0 +1,28 @@
#include <dawn/native/DawnNative.h>
#include "mach_dawn.h"
#if defined(__APPLE__)
namespace dawn::native::metal {
DAWN_NATIVE_EXPORT void WaitForCommandsToBeScheduled(WGPUDevice device);
} // namespace dawn::native
#endif // defined(__APPLE__)
#ifdef __cplusplus
extern "C" {
#endif
MACH_EXPORT const DawnProcTable machDawnGetProcTable() {
return dawn::native::GetProcs();
}
MACH_EXPORT void machDawnDeviceWaitForCommandsToBeScheduled(WGPUDevice device) {
#if defined(__APPLE__)
return dawn::native::metal::WaitForCommandsToBeScheduled(device);
#else
return;
#endif // defined(__APPLE__)
}
#ifdef __cplusplus
} // extern "C"
#endif

36
src/gpu/mach_dawn.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef MACH_DAWN_C_H_
#define MACH_DAWN_C_H_
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MACH_DAWN_C_SHARED_LIBRARY)
# if defined(_WIN32)
# if defined(MACH_DAWN_C_IMPLEMENTATION)
# define MACH_EXPORT __declspec(dllexport)
# else
# define MACH_EXPORT __declspec(dllimport)
# endif
# else // defined(_WIN32)
# if defined(MACH_DAWN_C_IMPLEMENTATION)
# define MACH_EXPORT __attribute__((visibility("default")))
# else
# define MACH_EXPORT
# endif
# endif // defined(_WIN32)
#else // defined(MACH_DAWN_C_SHARED_LIBRARY)
# define MACH_EXPORT
#endif // defined(MACH_DAWN_C_SHARED_LIBRARY)
#include <dawn/webgpu.h>
#include <dawn/dawn_proc_table.h>
MACH_EXPORT const DawnProcTable machDawnGetProcTable();
MACH_EXPORT void machDawnDeviceWaitForCommandsToBeScheduled(WGPUDevice device);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // MACH_DAWN_C_H_

1025
src/gpu/main.zig Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const BindGroupLayout = @import("bind_group_layout.zig").BindGroupLayout;
const Impl = @import("interface.zig").Impl;
pub const PipelineLayout = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
bind_group_layout_count: usize = 0,
bind_group_layouts: ?[*]const *BindGroupLayout = null,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
bind_group_layouts: ?[]const *BindGroupLayout = null,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.bind_group_layout_count = if (v.bind_group_layouts) |e| e.len else 0,
.bind_group_layouts = if (v.bind_group_layouts) |e| e.ptr else null,
};
}
};
pub inline fn setLabel(pipeline_layout: *PipelineLayout, label: [*:0]const u8) void {
Impl.pipelineLayoutSetLabel(pipeline_layout, label);
}
pub inline fn reference(pipeline_layout: *PipelineLayout) void {
Impl.pipelineLayoutReference(pipeline_layout);
}
pub inline fn release(pipeline_layout: *PipelineLayout) void {
Impl.pipelineLayoutRelease(pipeline_layout);
}
};

57
src/gpu/query_set.zig Normal file
View file

@ -0,0 +1,57 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const PipelineStatisticName = @import("main.zig").PipelineStatisticName;
const QueryType = @import("main.zig").QueryType;
const Impl = @import("interface.zig").Impl;
pub const QuerySet = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
type: QueryType,
count: u32,
pipeline_statistics: ?[*]const PipelineStatisticName = null,
pipeline_statistics_count: usize = 0,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
type: QueryType,
count: u32,
pipeline_statistics: ?[]const PipelineStatisticName = null,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.type = v.type,
.count = v.count,
.pipeline_statistics_count = if (v.pipeline_statistics) |e| e.len else 0,
.pipeline_statistics = if (v.pipeline_statistics) |e| e.ptr else null,
};
}
};
pub inline fn destroy(query_set: *QuerySet) void {
Impl.querySetDestroy(query_set);
}
pub inline fn getCount(query_set: *QuerySet) u32 {
return Impl.querySetGetCount(query_set);
}
pub inline fn getType(query_set: *QuerySet) QueryType {
return Impl.querySetGetType(query_set);
}
pub inline fn setLabel(query_set: *QuerySet, label: [*:0]const u8) void {
Impl.querySetSetLabel(query_set, label);
}
pub inline fn reference(query_set: *QuerySet) void {
Impl.querySetReference(query_set);
}
pub inline fn release(query_set: *QuerySet) void {
Impl.querySetRelease(query_set);
}
};

101
src/gpu/queue.zig Normal file
View file

@ -0,0 +1,101 @@
const std = @import("std");
const CommandBuffer = @import("command_buffer.zig").CommandBuffer;
const Buffer = @import("buffer.zig").Buffer;
const Texture = @import("texture.zig").Texture;
const ImageCopyTexture = @import("main.zig").ImageCopyTexture;
const ImageCopyExternalTexture = @import("main.zig").ImageCopyExternalTexture;
const ChainedStruct = @import("main.zig").ChainedStruct;
const Extent3D = @import("main.zig").Extent3D;
const CopyTextureForBrowserOptions = @import("main.zig").CopyTextureForBrowserOptions;
const Impl = @import("interface.zig").Impl;
pub const Queue = opaque {
pub const WorkDoneCallback = *const fn (
status: WorkDoneStatus,
userdata: ?*anyopaque,
) callconv(.C) void;
pub const WorkDoneStatus = enum(u32) {
success = 0x00000000,
err = 0x00000001,
unknown = 0x00000002,
device_lost = 0x00000003,
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
};
pub inline fn copyExternalTextureForBrowser(queue: *Queue, source: *const ImageCopyExternalTexture, destination: *const ImageCopyTexture, copy_size: *const Extent3D, options: *const CopyTextureForBrowserOptions) void {
Impl.queueCopyExternalTextureForBrowser(queue, source, destination, copy_size, options);
}
pub inline fn copyTextureForBrowser(queue: *Queue, source: *const ImageCopyTexture, destination: *const ImageCopyTexture, copy_size: *const Extent3D, options: *const CopyTextureForBrowserOptions) void {
Impl.queueCopyTextureForBrowser(queue, source, destination, copy_size, options);
}
// TODO: dawn: does not allow unsetting this callback to null
pub inline fn onSubmittedWorkDone(
queue: *Queue,
signal_value: u64,
context: anytype,
comptime callback: fn (ctx: @TypeOf(context), status: WorkDoneStatus) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(status: WorkDoneStatus, userdata: ?*anyopaque) callconv(.C) void {
callback(if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))), status);
}
};
Impl.queueOnSubmittedWorkDone(queue, signal_value, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn setLabel(queue: *Queue, label: [*:0]const u8) void {
Impl.queueSetLabel(queue, label);
}
pub inline fn submit(queue: *Queue, commands: []const *const CommandBuffer) void {
Impl.queueSubmit(queue, commands.len, commands.ptr);
}
pub inline fn writeBuffer(
queue: *Queue,
buffer: *Buffer,
buffer_offset_bytes: u64,
data_slice: anytype,
) void {
Impl.queueWriteBuffer(
queue,
buffer,
buffer_offset_bytes,
@as(*const anyopaque, @ptrCast(std.mem.sliceAsBytes(data_slice).ptr)),
data_slice.len * @sizeOf(std.meta.Elem(@TypeOf(data_slice))),
);
}
pub inline fn writeTexture(
queue: *Queue,
destination: *const ImageCopyTexture,
data_layout: *const Texture.DataLayout,
write_size: *const Extent3D,
data_slice: anytype,
) void {
Impl.queueWriteTexture(
queue,
destination,
@as(*const anyopaque, @ptrCast(std.mem.sliceAsBytes(data_slice).ptr)),
@as(usize, @intCast(data_slice.len)) * @sizeOf(std.meta.Elem(@TypeOf(data_slice))),
data_layout,
write_size,
);
}
pub inline fn reference(queue: *Queue) void {
Impl.queueReference(queue);
}
pub inline fn release(queue: *Queue) void {
Impl.queueRelease(queue);
}
};

21
src/gpu/render_bundle.zig Normal file
View file

@ -0,0 +1,21 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const Impl = @import("interface.zig").Impl;
pub const RenderBundle = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
};
pub inline fn setLabel(render_bundle: *RenderBundle, label: [*:0]const u8) void {
Impl.renderBundleSetLabel(render_bundle, label);
}
pub inline fn reference(render_bundle: *RenderBundle) void {
Impl.renderBundleReference(render_bundle);
}
pub inline fn release(render_bundle: *RenderBundle) void {
Impl.renderBundleRelease(render_bundle);
}
};

View file

@ -0,0 +1,122 @@
const Texture = @import("texture.zig").Texture;
const Buffer = @import("buffer.zig").Buffer;
const BindGroup = @import("bind_group.zig").BindGroup;
const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
const RenderBundle = @import("render_bundle.zig").RenderBundle;
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const IndexFormat = @import("main.zig").IndexFormat;
const Impl = @import("interface.zig").Impl;
pub const RenderBundleEncoder = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
color_formats_count: usize = 0,
color_formats: ?[*]const Texture.Format = null,
depth_stencil_format: Texture.Format = .undefined,
sample_count: u32 = 1,
depth_read_only: Bool32 = .false,
stencil_read_only: Bool32 = .false,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
color_formats: ?[]const Texture.Format = null,
depth_stencil_format: Texture.Format = .undefined,
sample_count: u32 = 1,
depth_read_only: bool = false,
stencil_read_only: bool = false,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.color_formats_count = if (v.color_formats) |e| e.len else 0,
.color_formats = if (v.color_formats) |e| e.ptr else null,
.depth_stencil_format = v.depth_stencil_format,
.sample_count = v.sample_count,
.depth_read_only = Bool32.from(v.depth_read_only),
.stencil_read_only = Bool32.from(v.stencil_read_only),
};
}
};
/// Default `instance_count`: 1
/// Default `first_vertex`: 0
/// Default `first_instance`: 0
pub inline fn draw(render_bundle_encoder: *RenderBundleEncoder, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void {
Impl.renderBundleEncoderDraw(render_bundle_encoder, vertex_count, instance_count, first_vertex, first_instance);
}
/// Default `instance_count`: 1
/// Default `first_index`: 0
/// Default `base_vertex`: 0
/// Default `first_instance`: 0
pub inline fn drawIndexed(render_bundle_encoder: *RenderBundleEncoder, index_count: u32, instance_count: u32, first_index: u32, base_vertex: i32, first_instance: u32) void {
Impl.renderBundleEncoderDrawIndexed(render_bundle_encoder, index_count, instance_count, first_index, base_vertex, first_instance);
}
pub inline fn drawIndexedIndirect(render_bundle_encoder: *RenderBundleEncoder, indirect_buffer: *Buffer, indirect_offset: u64) void {
Impl.renderBundleEncoderDrawIndexedIndirect(render_bundle_encoder, indirect_buffer, indirect_offset);
}
pub inline fn drawIndirect(render_bundle_encoder: *RenderBundleEncoder, indirect_buffer: *Buffer, indirect_offset: u64) void {
Impl.renderBundleEncoderDrawIndirect(render_bundle_encoder, indirect_buffer, indirect_offset);
}
pub inline fn finish(render_bundle_encoder: *RenderBundleEncoder, descriptor: ?*const RenderBundle.Descriptor) *RenderBundle {
return Impl.renderBundleEncoderFinish(render_bundle_encoder, descriptor);
}
pub inline fn insertDebugMarker(render_bundle_encoder: *RenderBundleEncoder, marker_label: [*:0]const u8) void {
Impl.renderBundleEncoderInsertDebugMarker(render_bundle_encoder, marker_label);
}
pub inline fn popDebugGroup(render_bundle_encoder: *RenderBundleEncoder) void {
Impl.renderBundleEncoderPopDebugGroup(render_bundle_encoder);
}
pub inline fn pushDebugGroup(render_bundle_encoder: *RenderBundleEncoder, group_label: [*:0]const u8) void {
Impl.renderBundleEncoderPushDebugGroup(render_bundle_encoder, group_label);
}
/// Default `dynamic_offsets`: `null`
pub inline fn setBindGroup(render_bundle_encoder: *RenderBundleEncoder, group_index: u32, group: *BindGroup, dynamic_offsets: ?[]const u32) void {
Impl.renderBundleEncoderSetBindGroup(
render_bundle_encoder,
group_index,
group,
if (dynamic_offsets) |v| v.len else 0,
if (dynamic_offsets) |v| v.ptr else null,
);
}
/// Default `offset`: 0
/// Default `size`: `gpu.whole_size`
pub inline fn setIndexBuffer(render_bundle_encoder: *RenderBundleEncoder, buffer: *Buffer, format: IndexFormat, offset: u64, size: u64) void {
Impl.renderBundleEncoderSetIndexBuffer(render_bundle_encoder, buffer, format, offset, size);
}
pub inline fn setLabel(render_bundle_encoder: *RenderBundleEncoder, label: [*:0]const u8) void {
Impl.renderBundleEncoderSetLabel(render_bundle_encoder, label);
}
pub inline fn setPipeline(render_bundle_encoder: *RenderBundleEncoder, pipeline: *RenderPipeline) void {
Impl.renderBundleEncoderSetPipeline(render_bundle_encoder, pipeline);
}
/// Default `offset`: 0
/// Default `size`: `gpu.whole_size`
pub inline fn setVertexBuffer(render_bundle_encoder: *RenderBundleEncoder, slot: u32, buffer: *Buffer, offset: u64, size: u64) void {
Impl.renderBundleEncoderSetVertexBuffer(render_bundle_encoder, slot, buffer, offset, size);
}
pub inline fn reference(render_bundle_encoder: *RenderBundleEncoder) void {
Impl.renderBundleEncoderReference(render_bundle_encoder);
}
pub inline fn release(render_bundle_encoder: *RenderBundleEncoder) void {
Impl.renderBundleEncoderRelease(render_bundle_encoder);
}
};

View file

@ -0,0 +1,128 @@
const Buffer = @import("buffer.zig").Buffer;
const RenderBundle = @import("render_bundle.zig").RenderBundle;
const BindGroup = @import("bind_group.zig").BindGroup;
const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
const QuerySet = @import("query_set.zig").QuerySet;
const Color = @import("main.zig").Color;
const IndexFormat = @import("main.zig").IndexFormat;
const Impl = @import("interface.zig").Impl;
pub const RenderPassEncoder = opaque {
pub inline fn beginOcclusionQuery(render_pass_encoder: *RenderPassEncoder, query_index: u32) void {
Impl.renderPassEncoderBeginOcclusionQuery(render_pass_encoder, query_index);
}
/// Default `instance_count`: 1
/// Default `first_vertex`: 0
/// Default `first_instance`: 0
pub inline fn draw(render_pass_encoder: *RenderPassEncoder, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void {
Impl.renderPassEncoderDraw(render_pass_encoder, vertex_count, instance_count, first_vertex, first_instance);
}
/// Default `instance_count`: 1
/// Default `first_index`: 0
/// Default `base_vertex`: 0
/// Default `first_instance`: 0
pub inline fn drawIndexed(render_pass_encoder: *RenderPassEncoder, index_count: u32, instance_count: u32, first_index: u32, base_vertex: i32, first_instance: u32) void {
Impl.renderPassEncoderDrawIndexed(render_pass_encoder, index_count, instance_count, first_index, base_vertex, first_instance);
}
pub inline fn drawIndexedIndirect(render_pass_encoder: *RenderPassEncoder, indirect_buffer: *Buffer, indirect_offset: u64) void {
Impl.renderPassEncoderDrawIndexedIndirect(render_pass_encoder, indirect_buffer, indirect_offset);
}
pub inline fn drawIndirect(render_pass_encoder: *RenderPassEncoder, indirect_buffer: *Buffer, indirect_offset: u64) void {
Impl.renderPassEncoderDrawIndirect(render_pass_encoder, indirect_buffer, indirect_offset);
}
pub inline fn end(render_pass_encoder: *RenderPassEncoder) void {
Impl.renderPassEncoderEnd(render_pass_encoder);
}
pub inline fn endOcclusionQuery(render_pass_encoder: *RenderPassEncoder) void {
Impl.renderPassEncoderEndOcclusionQuery(render_pass_encoder);
}
pub inline fn executeBundles(
render_pass_encoder: *RenderPassEncoder,
bundles: []*const RenderBundle,
) void {
Impl.renderPassEncoderExecuteBundles(
render_pass_encoder,
bundles.len,
bundles.ptr,
);
}
pub inline fn insertDebugMarker(render_pass_encoder: *RenderPassEncoder, marker_label: [*:0]const u8) void {
Impl.renderPassEncoderInsertDebugMarker(render_pass_encoder, marker_label);
}
pub inline fn popDebugGroup(render_pass_encoder: *RenderPassEncoder) void {
Impl.renderPassEncoderPopDebugGroup(render_pass_encoder);
}
pub inline fn pushDebugGroup(render_pass_encoder: *RenderPassEncoder, group_label: [*:0]const u8) void {
Impl.renderPassEncoderPushDebugGroup(render_pass_encoder, group_label);
}
/// Default `dynamic_offsets_count`: 0
/// Default `dynamic_offsets`: `null`
pub inline fn setBindGroup(render_pass_encoder: *RenderPassEncoder, group_index: u32, group: *BindGroup, dynamic_offsets: ?[]const u32) void {
Impl.renderPassEncoderSetBindGroup(
render_pass_encoder,
group_index,
group,
if (dynamic_offsets) |v| v.len else 0,
if (dynamic_offsets) |v| v.ptr else null,
);
}
pub inline fn setBlendConstant(render_pass_encoder: *RenderPassEncoder, color: *const Color) void {
Impl.renderPassEncoderSetBlendConstant(render_pass_encoder, color);
}
/// Default `offset`: 0
/// Default `size`: `gpu.whole_size`
pub inline fn setIndexBuffer(render_pass_encoder: *RenderPassEncoder, buffer: *Buffer, format: IndexFormat, offset: u64, size: u64) void {
Impl.renderPassEncoderSetIndexBuffer(render_pass_encoder, buffer, format, offset, size);
}
pub inline fn setLabel(render_pass_encoder: *RenderPassEncoder, label: [*:0]const u8) void {
Impl.renderPassEncoderSetLabel(render_pass_encoder, label);
}
pub inline fn setPipeline(render_pass_encoder: *RenderPassEncoder, pipeline: *RenderPipeline) void {
Impl.renderPassEncoderSetPipeline(render_pass_encoder, pipeline);
}
pub inline fn setScissorRect(render_pass_encoder: *RenderPassEncoder, x: u32, y: u32, width: u32, height: u32) void {
Impl.renderPassEncoderSetScissorRect(render_pass_encoder, x, y, width, height);
}
pub inline fn setStencilReference(render_pass_encoder: *RenderPassEncoder, _reference: u32) void {
Impl.renderPassEncoderSetStencilReference(render_pass_encoder, _reference);
}
/// Default `offset`: 0
/// Default `size`: `gpu.whole_size`
pub inline fn setVertexBuffer(render_pass_encoder: *RenderPassEncoder, slot: u32, buffer: *Buffer, offset: u64, size: u64) void {
Impl.renderPassEncoderSetVertexBuffer(render_pass_encoder, slot, buffer, offset, size);
}
pub inline fn setViewport(render_pass_encoder: *RenderPassEncoder, x: f32, y: f32, width: f32, height: f32, min_depth: f32, max_depth: f32) void {
Impl.renderPassEncoderSetViewport(render_pass_encoder, x, y, width, height, min_depth, max_depth);
}
pub inline fn writeTimestamp(render_pass_encoder: *RenderPassEncoder, query_set: *QuerySet, query_index: u32) void {
Impl.renderPassEncoderWriteTimestamp(render_pass_encoder, query_set, query_index);
}
pub inline fn reference(render_pass_encoder: *RenderPassEncoder) void {
Impl.renderPassEncoderReference(render_pass_encoder);
}
pub inline fn release(render_pass_encoder: *RenderPassEncoder) void {
Impl.renderPassEncoderRelease(render_pass_encoder);
}
};

View file

@ -0,0 +1,38 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const DepthStencilState = @import("main.zig").DepthStencilState;
const MultisampleState = @import("main.zig").MultisampleState;
const VertexState = @import("main.zig").VertexState;
const PrimitiveState = @import("main.zig").PrimitiveState;
const FragmentState = @import("main.zig").FragmentState;
const PipelineLayout = @import("pipeline_layout.zig").PipelineLayout;
const BindGroupLayout = @import("bind_group_layout.zig").BindGroupLayout;
const Impl = @import("interface.zig").Impl;
pub const RenderPipeline = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
layout: ?*PipelineLayout = null,
vertex: VertexState,
primitive: PrimitiveState = .{},
depth_stencil: ?*const DepthStencilState = null,
multisample: MultisampleState = .{},
fragment: ?*const FragmentState = null,
};
pub inline fn getBindGroupLayout(render_pipeline: *RenderPipeline, group_index: u32) *BindGroupLayout {
return Impl.renderPipelineGetBindGroupLayout(render_pipeline, group_index);
}
pub inline fn setLabel(render_pipeline: *RenderPipeline, label: [*:0]const u8) void {
Impl.renderPipelineSetLabel(render_pipeline, label);
}
pub inline fn reference(render_pipeline: *RenderPipeline) void {
Impl.renderPipelineReference(render_pipeline);
}
pub inline fn release(render_pipeline: *RenderPipeline) void {
Impl.renderPipelineRelease(render_pipeline);
}
};

52
src/gpu/sampler.zig Normal file
View file

@ -0,0 +1,52 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const FilterMode = @import("main.zig").FilterMode;
const MipmapFilterMode = @import("main.zig").MipmapFilterMode;
const CompareFunction = @import("main.zig").CompareFunction;
const Impl = @import("interface.zig").Impl;
pub const Sampler = opaque {
pub const AddressMode = enum(u32) {
repeat = 0x00000000,
mirror_repeat = 0x00000001,
clamp_to_edge = 0x00000002,
};
pub const BindingType = enum(u32) {
undefined = 0x00000000,
filtering = 0x00000001,
non_filtering = 0x00000002,
comparison = 0x00000003,
};
pub const BindingLayout = extern struct {
next_in_chain: ?*const ChainedStruct = null,
type: BindingType = .undefined,
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
address_mode_u: AddressMode = .clamp_to_edge,
address_mode_v: AddressMode = .clamp_to_edge,
address_mode_w: AddressMode = .clamp_to_edge,
mag_filter: FilterMode = .nearest,
min_filter: FilterMode = .nearest,
mipmap_filter: MipmapFilterMode = .nearest,
lod_min_clamp: f32 = 0.0,
lod_max_clamp: f32 = 32.0,
compare: CompareFunction = .undefined,
max_anisotropy: u16 = 1,
};
pub inline fn setLabel(sampler: *Sampler, label: [*:0]const u8) void {
Impl.samplerSetLabel(sampler, label);
}
pub inline fn reference(sampler: *Sampler) void {
Impl.samplerReference(sampler);
}
pub inline fn release(sampler: *Sampler) void {
Impl.samplerRelease(sampler);
}
};

69
src/gpu/shader_module.zig Normal file
View file

@ -0,0 +1,69 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const CompilationInfoCallback = @import("main.zig").CompilationInfoCallback;
const CompilationInfoRequestStatus = @import("main.zig").CompilationInfoRequestStatus;
const CompilationInfo = @import("main.zig").CompilationInfo;
const Impl = @import("interface.zig").Impl;
const dawn = @import("dawn.zig");
pub const ShaderModule = opaque {
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
spirv_descriptor: ?*const SPIRVDescriptor,
wgsl_descriptor: ?*const WGSLDescriptor,
dawn_shader_module_spirv_options_descriptor: ?*const dawn.ShaderModuleSPIRVOptionsDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
};
pub const SPIRVDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shader_module_spirv_descriptor },
code_size: u32,
code: [*]const u32,
};
pub const WGSLDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shader_module_wgsl_descriptor },
code: [*:0]const u8,
};
pub inline fn getCompilationInfo(
shader_module: *ShaderModule,
context: anytype,
comptime callback: fn (
ctx: @TypeOf(context),
status: CompilationInfoRequestStatus,
compilation_info: *const CompilationInfo,
) callconv(.Inline) void,
) void {
const Context = @TypeOf(context);
const Helper = struct {
pub fn cCallback(
status: CompilationInfoRequestStatus,
compilation_info: *const CompilationInfo,
userdata: ?*anyopaque,
) callconv(.C) void {
callback(
if (Context == void) {} else @as(Context, @ptrCast(@alignCast(userdata))),
status,
compilation_info,
);
}
};
Impl.shaderModuleGetCompilationInfo(shader_module, Helper.cCallback, if (Context == void) null else context);
}
pub inline fn setLabel(shader_module: *ShaderModule, label: [*:0]const u8) void {
Impl.shaderModuleSetLabel(shader_module, label);
}
pub inline fn reference(shader_module: *ShaderModule) void {
Impl.shaderModuleReference(shader_module);
}
pub inline fn release(shader_module: *ShaderModule) void {
Impl.shaderModuleRelease(shader_module);
}
};

91
src/gpu/shared_fence.zig Normal file
View file

@ -0,0 +1,91 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const ChainedStructOut = @import("main.zig").ChainedStructOut;
pub const SharedFence = opaque {
pub const Type = enum(u32) {
shared_fence_type_undefined = 0x00000000,
shared_fence_type_vk_semaphore_opaque_fd = 0x00000001,
shared_fence_type_vk_semaphore_sync_fd = 0x00000002,
shared_fence_type_vk_semaphore_zircon_handle = 0x00000003,
shared_fence_type_dxgi_shared_handle = 0x00000004,
shared_fence_type_mtl_shared_event = 0x00000005,
};
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
vk_semaphore_opaque_fd_descriptor: *const VkSemaphoreOpaqueFDDescriptor,
vk_semaphore_sync_fd_descriptor: *const VkSemaphoreSyncFDDescriptor,
vk_semaphore_zircon_handle_descriptor: *const VkSemaphoreZirconHandleDescriptor,
dxgi_shared_handle_descriptor: *const DXGISharedHandleDescriptor,
mtl_shared_event_descriptor: *const MTLSharedEventDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*]const u8,
};
pub const DXGISharedHandleDescriptor = extern struct {
chain: ChainedStruct,
handle: *anyopaque,
};
pub const DXGISharedHandleExportInfo = extern struct {
chain: ChainedStructOut,
handle: *anyopaque,
};
pub const ExportInfo = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStructOut,
dxgi_shared_handle_export_info: *const DXGISharedHandleExportInfo,
mtl_shared_event_export_info: *const MTLSharedEventExportInfo,
vk_semaphore_opaque_fd_export_info: *const VkSemaphoreOpaqueFDExportInfo,
vk_semaphore_sync_fd_export_info: *const VkSemaphoreSyncFDExportInfo,
vk_semaphore_zircon_handle_export_info: *const VkSemaphoreZirconHandleExportInfo,
};
next_in_chain: NextInChain = .{ .generic = null },
type: Type,
};
pub const MTLSharedEventDescriptor = extern struct {
chain: ChainedStruct,
shared_event: *anyopaque,
};
pub const MTLSharedEventExportInfo = extern struct {
chain: ChainedStructOut,
shared_event: *anyopaque,
};
pub const VkSemaphoreOpaqueFDDescriptor = extern struct {
chain: ChainedStruct,
handle: c_int,
};
pub const VkSemaphoreOpaqueFDExportInfo = extern struct {
chain: ChainedStructOut,
handle: c_int,
};
pub const VkSemaphoreSyncFDDescriptor = extern struct {
chain: ChainedStruct,
handle: c_int,
};
pub const VkSemaphoreSyncFDExportInfo = extern struct {
chain: ChainedStructOut,
handle: c_int,
};
pub const VkSemaphoreZirconHandleDescriptor = extern struct {
chain: ChainedStruct,
handle: u32,
};
pub const VkSemaphoreZirconHandleExportInfo = extern struct {
chain: ChainedStructOut,
handle: u32,
};
};

View file

@ -0,0 +1,124 @@
const Texture = @import("texture.zig").Texture;
const Bool32 = @import("main.zig").Bool32;
const Extent3D = @import("main.zig").Extent3D;
const SharedFence = @import("shared_fence.zig").SharedFence;
const ChainedStruct = @import("main.zig").ChainedStruct;
const ChainedStructOut = @import("main.zig").ChainedStructOut;
pub const SharedTextureMemory = opaque {
pub const Properties = extern struct {
next_in_chain: *const ChainedStruct,
usage: Texture.UsageFlags,
size: Extent3D,
format: Texture.Format,
};
pub const VkImageDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_vk_image_descriptor },
vk_format: i32,
vk_usage_flags: Texture.UsageFlags,
vk_extent3D: Extent3D,
};
pub const AHardwareBufferDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_a_hardware_buffer_descriptor },
handle: *anyopaque,
};
pub const BeginAccessDescriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
vk_image_layout_begin_state: *const VkImageLayoutBeginState,
};
next_in_chain: NextInChain = .{ .generic = null },
initialized: Bool32,
fence_count: usize,
fences: *const SharedFence,
signaled_values: *const u64,
};
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
a_hardware_buffer_descriptor: *const AHardwareBufferDescriptor,
dma_buf_descriptor: *const DmaBufDescriptor,
dxgi_shared_handle_descriptor: *const DXGISharedHandleDescriptor,
egl_image_descriptor: *const EGLImageDescriptor,
io_surface_descriptor: *const IOSurfaceDescriptor,
opaque_fd_descriptor: *const OpaqueFDDescriptor,
vk_dedicated_allocation_descriptor: *const VkDedicatedAllocationDescriptor,
zircon_handle_descriptor: *const ZirconHandleDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*]const u8,
};
pub const DmaBufDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_dma_buf_descriptor },
memory_fd: c_int,
allocation_size: u64,
drm_modifier: u64,
plane_count: usize,
plane_offsets: *const u64,
plane_strides: *const u32,
};
pub const DXGISharedHandleDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_dxgi_shared_handle_descriptor },
handle: *anyopaque,
};
pub const EGLImageDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_egl_image_descriptor },
image: *anyopaque,
};
pub const EndAccessState = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
vk_image_layout_end_state: *const VkImageLayoutEndState,
};
next_in_chain: NextInChain = .{ .generic = null },
initialized: Bool32,
fence_count: usize,
fences: *const SharedFence,
signaled_values: *const u64,
};
pub const IOSurfaceDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_io_surface_descriptor },
ioSurface: *anyopaque,
};
pub const OpaqueFDDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_opaque_fd_descriptor },
memory_fd: c_int,
allocation_size: u64,
};
pub const VkDedicatedAllocationDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_vk_dedicated_allocation_descriptor },
dedicated_allocation: Bool32,
};
pub const VkImageLayoutBeginState = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_vk_image_layout_begin_state },
old_layout: i32,
new_layout: i32,
};
pub const VkImageLayoutEndState = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_vk_image_layout_end_state },
old_layout: i32,
new_layout: i32,
};
pub const ZirconHandleDescriptor = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .shared_texture_memory_zircon_handle_descriptor },
memory_fd: u32,
allocation_size: u64,
};
};

72
src/gpu/surface.zig Normal file
View file

@ -0,0 +1,72 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const Impl = @import("interface.zig").Impl;
pub const Surface = opaque {
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
from_android_native_window: *const DescriptorFromAndroidNativeWindow,
from_canvas_html_selector: *const DescriptorFromCanvasHTMLSelector,
from_metal_layer: *const DescriptorFromMetalLayer,
from_wayland_surface: *const DescriptorFromWaylandSurface,
from_windows_core_window: *const DescriptorFromWindowsCoreWindow,
from_windows_hwnd: *const DescriptorFromWindowsHWND,
from_windows_swap_chain_panel: *const DescriptorFromWindowsSwapChainPanel,
from_xlib_window: *const DescriptorFromXlibWindow,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
};
pub const DescriptorFromAndroidNativeWindow = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_android_native_window },
window: *anyopaque,
};
pub const DescriptorFromCanvasHTMLSelector = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_canvas_html_selector },
selector: [*:0]const u8,
};
pub const DescriptorFromMetalLayer = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_metal_layer },
layer: *anyopaque,
};
pub const DescriptorFromWaylandSurface = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_wayland_surface },
display: *anyopaque,
surface: *anyopaque,
};
pub const DescriptorFromWindowsCoreWindow = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_windows_core_window },
core_window: *anyopaque,
};
pub const DescriptorFromWindowsHWND = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_windows_hwnd },
hinstance: *anyopaque,
hwnd: *anyopaque,
};
pub const DescriptorFromWindowsSwapChainPanel = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_windows_swap_chain_panel },
swap_chain_panel: *anyopaque,
};
pub const DescriptorFromXlibWindow = extern struct {
chain: ChainedStruct = .{ .next = null, .s_type = .surface_descriptor_from_xlib_window },
display: *anyopaque,
window: u32,
};
pub inline fn reference(surface: *Surface) void {
Impl.surfaceReference(surface);
}
pub inline fn release(surface: *Surface) void {
Impl.surfaceRelease(surface);
}
};

37
src/gpu/swap_chain.zig Normal file
View file

@ -0,0 +1,37 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const PresentMode = @import("main.zig").PresentMode;
const Texture = @import("texture.zig").Texture;
const TextureView = @import("texture_view.zig").TextureView;
const Impl = @import("interface.zig").Impl;
pub const SwapChain = opaque {
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
usage: Texture.UsageFlags,
format: Texture.Format,
width: u32,
height: u32,
present_mode: PresentMode,
};
pub inline fn getCurrentTexture(swap_chain: *SwapChain) ?*Texture {
return Impl.swapChainGetCurrentTexture(swap_chain);
}
pub inline fn getCurrentTextureView(swap_chain: *SwapChain) ?*TextureView {
return Impl.swapChainGetCurrentTextureView(swap_chain);
}
pub inline fn present(swap_chain: *SwapChain) void {
Impl.swapChainPresent(swap_chain);
}
pub inline fn reference(swap_chain: *SwapChain) void {
Impl.swapChainReference(swap_chain);
}
pub inline fn release(swap_chain: *SwapChain) void {
Impl.swapChainRelease(swap_chain);
}
};

266
src/gpu/texture.zig Normal file
View file

@ -0,0 +1,266 @@
const std = @import("std");
const Bool32 = @import("main.zig").Bool32;
const ChainedStruct = @import("main.zig").ChainedStruct;
const TextureView = @import("texture_view.zig").TextureView;
const Extent3D = @import("main.zig").Extent3D;
const Impl = @import("interface.zig").Impl;
const types = @import("main.zig");
const dawn = @import("dawn.zig");
pub const Texture = opaque {
pub const Aspect = enum(u32) {
all = 0x00000000,
stencil_only = 0x00000001,
depth_only = 0x00000002,
plane0_only = 0x00000003,
plane1_only = 0x00000004,
};
pub const Dimension = enum(u32) {
dimension_1d = 0x00000000,
dimension_2d = 0x00000001,
dimension_3d = 0x00000002,
};
pub const Format = enum(u32) {
undefined = 0x00000000,
r8_unorm = 0x00000001,
r8_snorm = 0x00000002,
r8_uint = 0x00000003,
r8_sint = 0x00000004,
r16_uint = 0x00000005,
r16_sint = 0x00000006,
r16_float = 0x00000007,
rg8_unorm = 0x00000008,
rg8_snorm = 0x00000009,
rg8_uint = 0x0000000a,
rg8_sint = 0x0000000b,
r32_float = 0x0000000c,
r32_uint = 0x0000000d,
r32_sint = 0x0000000e,
rg16_uint = 0x0000000f,
rg16_sint = 0x00000010,
rg16_float = 0x00000011,
rgba8_unorm = 0x00000012,
rgba8_unorm_srgb = 0x00000013,
rgba8_snorm = 0x00000014,
rgba8_uint = 0x00000015,
rgba8_sint = 0x00000016,
bgra8_unorm = 0x00000017,
bgra8_unorm_srgb = 0x00000018,
rgb10_a2_unorm = 0x00000019,
rg11_b10_ufloat = 0x0000001a,
rgb9_e5_ufloat = 0x0000001b,
rg32_float = 0x0000001c,
rg32_uint = 0x0000001d,
rg32_sint = 0x0000001e,
rgba16_uint = 0x0000001f,
rgba16_sint = 0x00000020,
rgba16_float = 0x00000021,
rgba32_float = 0x00000022,
rgba32_uint = 0x00000023,
rgba32_sint = 0x00000024,
stencil8 = 0x00000025,
depth16_unorm = 0x00000026,
depth24_plus = 0x00000027,
depth24_plus_stencil8 = 0x00000028,
depth32_float = 0x00000029,
depth32_float_stencil8 = 0x0000002a,
bc1_rgba_unorm = 0x0000002b,
bc1_rgba_unorm_srgb = 0x0000002c,
bc2_rgba_unorm = 0x0000002d,
bc2_rgba_unorm_srgb = 0x0000002e,
bc3_rgba_unorm = 0x0000002f,
bc3_rgba_unorm_srgb = 0x00000030,
bc4_runorm = 0x00000031,
bc4_rsnorm = 0x00000032,
bc5_rg_unorm = 0x00000033,
bc5_rg_snorm = 0x00000034,
bc6_hrgb_ufloat = 0x00000035,
bc6_hrgb_float = 0x00000036,
bc7_rgba_unorm = 0x00000037,
bc7_rgba_unorm_srgb = 0x00000038,
etc2_rgb8_unorm = 0x00000039,
etc2_rgb8_unorm_srgb = 0x0000003a,
etc2_rgb8_a1_unorm = 0x0000003b,
etc2_rgb8_a1_unorm_srgb = 0x0000003c,
etc2_rgba8_unorm = 0x0000003d,
etc2_rgba8_unorm_srgb = 0x0000003e,
eacr11_unorm = 0x0000003f,
eacr11_snorm = 0x00000040,
eacrg11_unorm = 0x00000041,
eacrg11_snorm = 0x00000042,
astc4x4_unorm = 0x00000043,
astc4x4_unorm_srgb = 0x00000044,
astc5x4_unorm = 0x00000045,
astc5x4_unorm_srgb = 0x00000046,
astc5x5_unorm = 0x00000047,
astc5x5_unorm_srgb = 0x00000048,
astc6x5_unorm = 0x00000049,
astc6x5_unorm_srgb = 0x0000004a,
astc6x6_unorm = 0x0000004b,
astc6x6_unorm_srgb = 0x0000004c,
astc8x5_unorm = 0x0000004d,
astc8x5_unorm_srgb = 0x0000004e,
astc8x6_unorm = 0x0000004f,
astc8x6_unorm_srgb = 0x00000050,
astc8x8_unorm = 0x00000051,
astc8x8_unorm_srgb = 0x00000052,
astc10x5_unorm = 0x00000053,
astc10x5_unorm_srgb = 0x00000054,
astc10x6_unorm = 0x00000055,
astc10x6_unorm_srgb = 0x00000056,
astc10x8_unorm = 0x00000057,
astc10x8_unorm_srgb = 0x00000058,
astc10x10_unorm = 0x00000059,
astc10x10_unorm_srgb = 0x0000005a,
astc12x10_unorm = 0x0000005b,
astc12x10_unorm_srgb = 0x0000005c,
astc12x12_unorm = 0x0000005d,
astc12x12_unorm_srgb = 0x0000005e,
r8_bg8_biplanar420_unorm = 0x0000005f,
};
pub const SampleType = enum(u32) {
undefined = 0x00000000,
float = 0x00000001,
unfilterable_float = 0x00000002,
depth = 0x00000003,
sint = 0x00000004,
uint = 0x00000005,
};
pub const UsageFlags = packed struct(u32) {
copy_src: bool = false,
copy_dst: bool = false,
texture_binding: bool = false,
storage_binding: bool = false,
render_attachment: bool = false,
transient_attachment: bool = false,
_padding: u26 = 0,
comptime {
std.debug.assert(
@sizeOf(@This()) == @sizeOf(u32) and
@bitSizeOf(@This()) == @bitSizeOf(u32),
);
}
pub const none = UsageFlags{};
pub fn equal(a: UsageFlags, b: UsageFlags) bool {
return @as(u6, @truncate(@as(u32, @bitCast(a)))) == @as(u6, @truncate(@as(u32, @bitCast(b))));
}
};
pub const BindingLayout = extern struct {
next_in_chain: ?*const ChainedStruct = null,
sample_type: SampleType = .undefined,
view_dimension: TextureView.Dimension = .dimension_undefined,
multisampled: Bool32 = .false,
};
pub const DataLayout = extern struct {
next_in_chain: ?*const ChainedStruct = null,
offset: u64 = 0,
bytes_per_row: u32 = types.copy_stride_undefined,
rows_per_image: u32 = types.copy_stride_undefined,
};
pub const Descriptor = extern struct {
pub const NextInChain = extern union {
generic: ?*const ChainedStruct,
dawn_texture_internal_usage_descriptor: *const dawn.TextureInternalUsageDescriptor,
};
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
usage: UsageFlags,
dimension: Dimension = .dimension_2d,
size: Extent3D,
format: Format,
mip_level_count: u32 = 1,
sample_count: u32 = 1,
view_format_count: usize = 0,
view_formats: ?[*]const Format = null,
/// Provides a slightly friendlier Zig API to initialize this structure.
pub inline fn init(v: struct {
next_in_chain: NextInChain = .{ .generic = null },
label: ?[*:0]const u8 = null,
usage: UsageFlags,
dimension: Dimension = .dimension_2d,
size: Extent3D,
format: Format,
mip_level_count: u32 = 1,
sample_count: u32 = 1,
view_formats: ?[]const Format = null,
}) Descriptor {
return .{
.next_in_chain = v.next_in_chain,
.label = v.label,
.usage = v.usage,
.dimension = v.dimension,
.size = v.size,
.format = v.format,
.mip_level_count = v.mip_level_count,
.sample_count = v.sample_count,
.view_format_count = if (v.view_formats) |e| e.len else 0,
.view_formats = if (v.view_formats) |e| e.ptr else null,
};
}
};
pub inline fn createView(texture: *Texture, descriptor: ?*const TextureView.Descriptor) *TextureView {
return Impl.textureCreateView(texture, descriptor);
}
pub inline fn destroy(texture: *Texture) void {
Impl.textureDestroy(texture);
}
pub inline fn getDepthOrArrayLayers(texture: *Texture) u32 {
return Impl.textureGetDepthOrArrayLayers(texture);
}
pub inline fn getDimension(texture: *Texture) Dimension {
return Impl.textureGetDimension(texture);
}
pub inline fn getFormat(texture: *Texture) Format {
return Impl.textureGetFormat(texture);
}
pub inline fn getHeight(texture: *Texture) u32 {
return Impl.textureGetHeight(texture);
}
pub inline fn getMipLevelCount(texture: *Texture) u32 {
return Impl.textureGetMipLevelCount(texture);
}
pub inline fn getSampleCount(texture: *Texture) u32 {
return Impl.textureGetSampleCount(texture);
}
pub inline fn getUsage(texture: *Texture) UsageFlags {
return Impl.textureGetUsage(texture);
}
pub inline fn getWidth(texture: *Texture) u32 {
return Impl.textureGetWidth(texture);
}
pub inline fn setLabel(texture: *Texture, label: [*:0]const u8) void {
Impl.textureSetLabel(texture, label);
}
pub inline fn reference(texture: *Texture) void {
Impl.textureReference(texture);
}
pub inline fn release(texture: *Texture) void {
Impl.textureRelease(texture);
}
};

40
src/gpu/texture_view.zig Normal file
View file

@ -0,0 +1,40 @@
const ChainedStruct = @import("main.zig").ChainedStruct;
const Texture = @import("texture.zig").Texture;
const Impl = @import("interface.zig").Impl;
const types = @import("main.zig");
pub const TextureView = opaque {
pub const Dimension = enum(u32) {
dimension_undefined = 0x00000000,
dimension_1d = 0x00000001,
dimension_2d = 0x00000002,
dimension_2d_array = 0x00000003,
dimension_cube = 0x00000004,
dimension_cube_array = 0x00000005,
dimension_3d = 0x00000006,
};
pub const Descriptor = extern struct {
next_in_chain: ?*const ChainedStruct = null,
label: ?[*:0]const u8 = null,
format: Texture.Format = .undefined,
dimension: Dimension = .dimension_undefined,
base_mip_level: u32 = 0,
mip_level_count: u32 = types.mip_level_count_undefined,
base_array_layer: u32 = 0,
array_layer_count: u32 = types.array_layer_count_undefined,
aspect: Texture.Aspect = .all,
};
pub inline fn setLabel(texture_view: *TextureView, label: [*:0]const u8) void {
Impl.textureViewSetLabel(texture_view, label);
}
pub inline fn reference(texture_view: *TextureView) void {
Impl.textureViewReference(texture_view);
}
pub inline fn release(texture_view: *TextureView) void {
Impl.textureViewRelease(texture_view);
}
};