Compare commits
3
Commits
0.1.0
...
bfac170936
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfac170936 | ||
|
|
523a9b69ac | ||
|
|
571a9db71f |
@@ -1,2 +1,3 @@
|
|||||||
.zig-cache
|
.zig-cache
|
||||||
zig-out
|
zig-out
|
||||||
|
examples/mnist
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Minimal Zig WebGPU Compute Library
|
# Minimal Zig WebGPU Compute Library
|
||||||
|
|
||||||
This is a minimal, self-contained Zig library designed to simplify running compute shaders using WebGPU. It abstracts away much of the boilerplate required for GPU device initialization, memory management, and pipeline execution.
|
This is a minimal, self-contained Zig library designed to simplify running compute shaders using WebGPU.
|
||||||
|
It abstracts away much of the boilerplate required for GPU device initialization, memory management, and pipeline execution.
|
||||||
|
|
||||||
## Core Modules
|
## Core Modules
|
||||||
|
|
||||||
@@ -81,3 +82,55 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
* **`wgpu.h`**: The library relies on the WebGPU C API headers to bind to the native system graphics.
|
* **`wgpu.h`**: The library relies on the WebGPU C API headers to bind to the native system graphics.
|
||||||
|
|
||||||
|
## System Requirements
|
||||||
|
|
||||||
|
Because this library binds to native system graphics APIs via `wgpu-native`,
|
||||||
|
you must ensure the appropriate development headers and libraries are available on your system before compiling.
|
||||||
|
|
||||||
|
### Linux (Vulkan)
|
||||||
|
You need the Vulkan development headers to compile the project, and a Vulkan-compatible driver to run it.
|
||||||
|
|
||||||
|
Depending on your distribution, install the following packages:
|
||||||
|
* **Ubuntu / Debian:**
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libvulkan-dev mesa-vulkan-drivers
|
||||||
|
```
|
||||||
|
* **Fedora / RHEL:**
|
||||||
|
```bash
|
||||||
|
sudo dnf install vulkan-devel mesa-vulkan-drivers
|
||||||
|
```
|
||||||
|
* **Arch Linux:**
|
||||||
|
```bash
|
||||||
|
sudo pacman -S vulkan-headers vulkan-icd-loader
|
||||||
|
```
|
||||||
|
|
||||||
|
### macOS (Metal)
|
||||||
|
No extra installation is required.
|
||||||
|
The build script automatically links against the standard Apple frameworks provided by the Xcode Command Line Tools
|
||||||
|
(`Metal`, `QuartzCore`, `Foundation`, `CoreGraphics`).
|
||||||
|
|
||||||
|
### Windows (DirectX 12)
|
||||||
|
No extra installation is required.
|
||||||
|
The build script automatically links against the standard Windows SDK libraries (`d3d12`, `dxgi`, `user32`).
|
||||||
|
Ensure you have the MSVC build tools installed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding to your project
|
||||||
|
|
||||||
|
To use this module in your own Zig project, add it to your `build.zig.zon`:
|
||||||
|
```bash
|
||||||
|
zig fetch --save git+https://git.bouvais.lu/adrien/zig-wgpu
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, in your `build.zig`, import and add the module to your executable:
|
||||||
|
```zig
|
||||||
|
const zig_wgpu = b.dependency("zig-wgpu", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe.root_module.addImport("gpu", zig_wgpu.module("zig-wgpu"));
|
||||||
|
```
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
// Define the module so other projects can import it
|
|
||||||
const mod = b.addModule("zig-wgpu", .{
|
const mod = b.addModule("zig-wgpu", .{
|
||||||
.root_source_file = b.path("src/lib.zig"),
|
.root_source_file = b.path("src/lib.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// I am using this mnist reduced dataset https://www.kaggle.com/datasets/mohamedgamal07/reduced-mnist
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const gpu = @import("gpu");
|
||||||
|
const GpuDevice = gpu.GpuDevice;
|
||||||
|
const GpuArena = gpu.GpuArena;
|
||||||
|
const GpuBuffer = gpu.GpuBuffer;
|
||||||
|
const GpuProcess = gpu.GpuProcess;
|
||||||
|
|
||||||
|
const BATCHSIZE = 10;
|
||||||
|
const EPOCH = 10;
|
||||||
|
|
||||||
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
const allocator = init.gpa;
|
||||||
|
const io = init.io;
|
||||||
|
|
||||||
|
// 1. Open GPU Device
|
||||||
|
const device = try GpuDevice.init(.{});
|
||||||
|
defer device.deinit();
|
||||||
|
|
||||||
|
// 2. Create a GPU Arena to manage VRAM
|
||||||
|
var grena = GpuArena.init(allocator, device);
|
||||||
|
defer grena.deinit();
|
||||||
|
const gloc = grena.gpuAllocator();
|
||||||
|
|
||||||
|
// 3. Load the WGSL compute pipeline
|
||||||
|
const add_process = try GpuProcess.init(device, @embedFile("shaders/add.wgsl"));
|
||||||
|
defer add_process.deinit();
|
||||||
|
|
||||||
|
var train_dir = try std.Io.Dir.cwd().openDir(io, "mnist/train", .{});
|
||||||
|
|
||||||
|
var images: [BATCHSIZE * 28 * 28]f16 = undefined;
|
||||||
|
for (EPOCH) |epoch| {
|
||||||
|
// Load random images from train dir
|
||||||
|
train_dir.openDir(io, "0", .{});
|
||||||
|
for (BATCHSIZE) |i| {
|
||||||
|
const file = try train_dir.openFile(io, "0.jpg", .{});
|
||||||
|
images[28 * 28 * i .. 28 * 28 * (i + 1)] = file.read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Setup CPU data
|
||||||
|
const len: usize = 16;
|
||||||
|
const data_a = try allocator.alloc(f16, len);
|
||||||
|
defer allocator.free(data_a);
|
||||||
|
const data_b = try allocator.alloc(f16, len);
|
||||||
|
defer allocator.free(data_b);
|
||||||
|
|
||||||
|
for (0..len) |i| {
|
||||||
|
data_a[i] = @floatFromInt(i);
|
||||||
|
data_b[i] = @floatFromInt(len - 1 - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Initialize raw GPU Buffers
|
||||||
|
// We pass the EnumSet inline using `.initMany` since the Enum itself isn't exported
|
||||||
|
const byte_size = len * @sizeOf(f16);
|
||||||
|
const buf_a = try GpuBuffer.init(gloc, byte_size, .initMany(&.{ .Storage, .CopyDst, .CopySrc }));
|
||||||
|
const buf_b = try GpuBuffer.init(gloc, byte_size, .initMany(&.{ .Storage, .CopyDst, .CopySrc }));
|
||||||
|
const buf_out = try GpuBuffer.init(gloc, byte_size, .initMany(&.{ .Storage, .CopyDst, .CopySrc }));
|
||||||
|
|
||||||
|
// Note: The buffers are safely tied to the GpuArena which will automatically
|
||||||
|
// release them at the end. You can also manually call buf_x.deinit() if desired.
|
||||||
|
|
||||||
|
// 6. Transfer data from CPU slices to GPU Buffers
|
||||||
|
try buf_a.load(f16, data_a);
|
||||||
|
try buf_b.load(f16, data_b);
|
||||||
|
|
||||||
|
// 7. Dispatch the Compute Process
|
||||||
|
// We pass the data type (f16) to allow GpuProcess to calculate chunks correctly
|
||||||
|
try add_process.run(gloc, f16, buf_a, buf_b, buf_out);
|
||||||
|
|
||||||
|
// 8. Map and copy the resulting buffer back to the CPU
|
||||||
|
const out = try buf_out.read(allocator, f16);
|
||||||
|
defer allocator.free(out);
|
||||||
|
|
||||||
|
std.debug.print("Result: {any}\n", .{out});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user