diff --git a/README.md b/README.md index c73ee1a..210a0b0 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,13 @@ The library exports five primary components: Below is a complete, self-contained example demonstrating how to initialize the GPU, load data, run a compute shader, and read the results back to the CPU: ```zig + const std = @import("std"); -const GpuDevice = @import("GpuDevice.zig"); -const GpuArena = @import("GpuArena.zig"); -const GpuBuffer = @import("GpuBuffer.zig"); -const GpuProcess = @import("GpuProcess.zig"); +const gpu = @import("gpu"); +const GpuDevice = gpu.GpuDevice; +const GpuArena = gpu.GpuArena; +const GpuBuffer = gpu.GpuBuffer; +const GpuProcess = gpu.GpuProcess; pub fn main(init: std.process.Init) !void { const allocator = init.gpa; diff --git a/build.zig b/build.zig index ea522f2..788717e 100644 --- a/build.zig +++ b/build.zig @@ -1,94 +1,60 @@ -// build.zig -// zig build run -// -// Expects wgpu-native pre-built in libs/wgpu-native/: -// include/wgpu.h -// lib/libwgpu_native.a (or .so / .dylib / .dll) -// -// Download release: https://github.com/gfx-rs/wgpu-native/releases -// Pick the archive matching your OS/arch, e.g.: -// wgpu-linux-x86_64-release.zip → libwgpu_native.a + wgpu.h -// wgpu-macos-aarch64-release.zip -// wgpu-windows-x86_64-msvc-release.zip - const std = @import("std"); -pub fn build(b: *std.Build) void { +pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - // 1. Define the module so other projects can import it - _ = b.addModule("zig-wgpu", .{ + // Define the module so other projects can import it + const mod = b.addModule("zig-wgpu", .{ .root_source_file = b.path("src/lib.zig"), + .target = target, }); - const exe = b.addExecutable(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("src/bench.zig"), - .link_libc = true, - .target = target, - .optimize = optimize, - }), - .name = "bench", - }); - - // wgpu-native headers + pre-built static library - exe.root_module.addIncludePath(b.path("libs/wgpu-native/include")); - exe.root_module.addLibraryPath(b.path("libs/wgpu-native/lib")); - exe.root_module.addObjectFile(b.path("libs/wgpu-native/lib/libwgpu_native.a")); + mod.addIncludePath(b.path("libs/wgpu-native/include")); + mod.addLibraryPath(b.path("libs/wgpu-native/lib")); + mod.addObjectFile(b.path("libs/wgpu-native/lib/libwgpu_native.a")); // Platform-specific system frameworks needed by wgpu-native const t = target.result; if (t.os.tag == .macos) { - exe.root_module.linkFramework("Metal", .{}); - exe.root_module.linkFramework("QuartzCore", .{}); - exe.root_module.linkFramework("Foundation", .{}); - exe.root_module.linkFramework("CoreGraphics", .{}); + mod.linkFramework("Metal", .{}); + mod.linkFramework("QuartzCore", .{}); + mod.linkFramework("Foundation", .{}); + mod.linkFramework("CoreGraphics", .{}); } else if (t.os.tag == .windows) { - exe.root_module.linkSystemLibrary("d3d12", .{}); - exe.root_module.linkSystemLibrary("dxgi", .{}); - exe.root_module.linkSystemLibrary("user32", .{}); + mod.linkSystemLibrary("d3d12", .{}); + mod.linkSystemLibrary("dxgi", .{}); + mod.linkSystemLibrary("user32", .{}); } else { - exe.root_module.linkSystemLibrary("vulkan", .{}); - exe.root_module.linkSystemLibrary("gcc_s", .{}); + mod.linkSystemLibrary("vulkan", .{}); + mod.linkSystemLibrary("gcc_s", .{}); } - b.installArtifact(exe); + var threaded: std.Io.Threaded = .init_single_threaded; + const io = threaded.io(); - const run = b.addRunArtifact(exe); - run.step.dependOn(b.getInstallStep()); - b.step("bench", "Benchmark a simple add vector.").dependOn(&run.step); + var buf: [1024]u8 = undefined; + const exemples = try std.Io.Dir.cwd().openDir(io, "examples", .{ .access_sub_paths = false, .iterate = true }); + var iter = exemples.iterate(); + while (try iter.next(io)) |entry| { + if (entry.kind != .file) continue; + if (!std.mem.eql(u8, entry.name[entry.name.len - 4 ..], ".zig")) continue; - const exe_examp = b.addExecutable(.{ - .root_module = b.createModule(.{ - .root_source_file = b.path("src/example.zig"), - .link_libc = true, - .target = target, - .optimize = optimize, - }), - .name = "bench", - }); + const exe = b.addExecutable(.{ + .name = entry.name[0 .. entry.name.len - 4], + .root_module = b.createModule(.{ + .root_source_file = b.path(try std.fmt.bufPrint(&buf, "examples/{s}", .{entry.name})), + .target = target, + .optimize = optimize, + .imports = &.{}, + }), + }); + exe.root_module.addImport("gpu", mod); - // wgpu-native headers + pre-built static library - exe_examp.root_module.addIncludePath(b.path("libs/wgpu-native/include")); - exe_examp.root_module.addLibraryPath(b.path("libs/wgpu-native/lib")); - exe_examp.root_module.addObjectFile(b.path("libs/wgpu-native/lib/libwgpu_native.a")); + b.installArtifact(exe); - if (t.os.tag == .macos) { - exe_examp.root_module.linkFramework("Metal", .{}); - exe_examp.root_module.linkFramework("QuartzCore", .{}); - exe_examp.root_module.linkFramework("Foundation", .{}); - exe_examp.root_module.linkFramework("CoreGraphics", .{}); - } else if (t.os.tag == .windows) { - exe_examp.root_module.linkSystemLibrary("d3d12", .{}); - exe_examp.root_module.linkSystemLibrary("dxgi", .{}); - exe_examp.root_module.linkSystemLibrary("user32", .{}); - } else { - exe_examp.root_module.linkSystemLibrary("vulkan", .{}); - exe_examp.root_module.linkSystemLibrary("gcc_s", .{}); + const run_step = b.step(entry.name[0 .. entry.name.len - 4], try std.fmt.bufPrint(&buf, "Run {s} demo", .{entry.name})); + const run_cmd = b.addRunArtifact(exe); + run_step.dependOn(&run_cmd.step); } - - const examp = b.addRunArtifact(exe_examp); - run.step.dependOn(b.getInstallStep()); - b.step("example", "Run basic example.").dependOn(&examp.step); } diff --git a/build.zig.zon b/build.zig.zon index 45b4fed..0678127 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,43 +1,13 @@ .{ - // This is the default name used by packages depending on this one. For - // example, when a user runs `zig fetch --save `, this field is used - // as the key in the `dependencies` table. Although the user can choose a - // different name, most users will stick with this provided value. - // - // It is redundant to include "zig" in this name because it is already - // within the Zig package namespace. .name = .zig_wgpu, - // This is a [Semantic Version](https://semver.org/). - // In a future version of Zig it will be used for package deduplication. - .version = "0.0.0", - // Together with name, this represents a globally unique package - // identifier. This field is generated by the Zig toolchain when the - // package is first created, and then *never changes*. This allows - // unambiguous detection of one package being an updated version of - // another. - // - // When forking a Zig project, this id should be regenerated (delete the - // field and run `zig build`) if the upstream project is still maintained. - // Otherwise, the fork is *hostile*, attempting to take control over the - // original project's identity. Thus it is recommended to leave the comment - // on the following line intact, so that it shows up in code reviews that - // modify the field. - .fingerprint = 0x5d0e853acbc0c2c6, // Changing this has security and trust implications. - // Tracks the earliest Zig version that the package considers to be a - // supported use case. + .version = "0.1.0", + .fingerprint = 0x5d0e853acbc0c2c6, .minimum_zig_version = "0.16.0", - // This field is optional. - // Each dependency must either provide a `url` and `hash`, or a `path`. - // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. - // Once all dependencies are fetched, `zig build` no longer requires - // internet connectivity. .dependencies = .{}, .paths = .{ "build.zig", "build.zig.zon", "src", - // For example... - //"LICENSE", - //"README.md", + "libs", }, } diff --git a/src/example.zig b/examples/add.zig similarity index 91% rename from src/example.zig rename to examples/add.zig index ff79b9d..ec73cef 100644 --- a/src/example.zig +++ b/examples/add.zig @@ -1,8 +1,9 @@ const std = @import("std"); -const GpuDevice = @import("GpuDevice.zig"); -const GpuArena = @import("GpuArena.zig"); -const GpuBuffer = @import("GpuBuffer.zig"); -const GpuProcess = @import("GpuProcess.zig"); +const gpu = @import("gpu"); +const GpuDevice = gpu.GpuDevice; +const GpuArena = gpu.GpuArena; +const GpuBuffer = gpu.GpuBuffer; +const GpuProcess = gpu.GpuProcess; pub fn main(init: std.process.Init) !void { const allocator = init.gpa; diff --git a/src/bench.zig b/examples/bench.zig similarity index 94% rename from src/bench.zig rename to examples/bench.zig index 762eb60..4138f47 100644 --- a/src/bench.zig +++ b/examples/bench.zig @@ -1,11 +1,10 @@ const std = @import("std"); -const GpuDevice = @import("GpuDevice.zig"); -const GpuArena = @import("GpuArena.zig"); -const GpuAllocator = @import("GpuAllocator.zig"); -const GpuBuffer = @import("GpuBuffer.zig"); -const GpuProcess = @import("GpuProcess.zig"); - -const c = @import("utils.zig").c; +const gpu = @import("gpu"); +const GpuDevice = gpu.GpuDevice; +const GpuArena = gpu.GpuArena; +const GpuAllocator = gpu.GpuAllocator; +const GpuBuffer = gpu.GpuBuffer; +const GpuProcess = gpu.GpuProcess; /// Minimal implementation of a f16 Vector const Vec = struct { @@ -80,9 +79,9 @@ pub fn main(init: std.process.Init) !void { 4 * 4 * 4 * 1024, 4 * 4 * 4 * 4 * 1024, 1024 * 1024, - // 4 * 1024 * 1024, - // 4 * 4 * 1024 * 1024, - // 4 * 4 * 4 * 1024 * 1024, + 4 * 1024 * 1024, + 4 * 4 * 1024 * 1024, + 4 * 4 * 4 * 1024 * 1024, // 4 * 4 * 4 * 4 * 1024 * 1024, // 4 * 4 * 4 * 4 * 4 * 1024 * 1024, }; @@ -137,7 +136,7 @@ pub fn main(init: std.process.Init) !void { if (grena.allocated_vram_bytes > peak_vram_bytes) peak_vram_bytes = grena.allocated_vram_bytes; - _ = c.wgpuDevicePoll(device.device, 1, null); + device.poll(); const compute_duration = compute_start.durationTo(std.Io.Clock.awake.now(init.io)); const compute_ns = @as(u64, @intCast(compute_duration.toNanoseconds())); diff --git a/src/shaders/add.wgsl b/examples/shaders/add.wgsl similarity index 100% rename from src/shaders/add.wgsl rename to examples/shaders/add.wgsl diff --git a/src/GpuDevice.zig b/src/GpuDevice.zig index b1f64ec..60c137f 100644 --- a/src/GpuDevice.zig +++ b/src/GpuDevice.zig @@ -93,6 +93,7 @@ pub fn deinit(self: @This()) void { c.wgpuInstanceRelease(self.instance); } +/// Wait for thing to be done pub fn poll(self: @This()) void { _ = c.wgpuDevicePoll(self.device, 1, null); }