diff --git a/build.zig b/build.zig index 421a8da..f4a70a9 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -fn link_windows_system_libraries(comptime T: type, mod: *T, is_gnu: bool) void { +pub fn link_windows_system_libraries(comptime T: type, mod: *T, is_gnu: bool) void { const linkSystemLibrary = switch (T) { std.Build.Module => std.Build.Module.linkSystemLibrary, std.Build.Step.Compile => std.Build.Step.Compile.linkSystemLibrary2, @@ -35,239 +35,61 @@ fn link_windows_system_libraries(comptime T: type, mod: *T, is_gnu: bool) void { // Needed by windows-rs (wgpu-native dependency) linkSystemLibrary(mod, "propsys", .{}); -} -fn link_mac_frameworks(mod: *std.Build.Step.Compile) void { - mod.linkFramework("Foundation"); - mod.linkFramework("QuartzCore"); - mod.linkFramework("Metal"); + // needed for tests? + linkSystemLibrary(mod, "unwind", .{}); } -const WGPUBuildContext = struct { - link_mode: std.builtin.LinkMode, - target: std.Build.ResolvedTarget, - optimize: std.builtin.OptimizeMode, - is_windows: bool, - is_mac: bool, - wgpu_dep: *std.Build.Dependency, - libwgpu_path: ?std.Build.LazyPath, - install_lib_dir: []const u8, - wgpu_mod: *std.Build.Module, - wgpu_c_mod: *std.Build.Module, - - fn init(b: *std.Build) ?WGPUBuildContext { - const link_mode = b.option(std.builtin.LinkMode, "link_mode", "Use static linking instead of dynamic linking.") orelse .static; - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. - const target = b.standardTargetOptions(.{}); - - // Standard optimization options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not - // set a preferred release mode, allowing the user to decide how to optimize. - const optimize = b.standardOptimizeOption(.{}); - - const target_res = target.result; - const os_str = @tagName(target_res.os.tag); - const arch_str = @tagName(target_res.cpu.arch); - - const mode_str = switch (optimize) { - .Debug => "debug", - else => "release", - }; - const abi_str = switch (target_res.os.tag) { - .ios => switch (target_res.abi) { - .simulator => "_simulator", - else => "", - }, - .windows => switch (target_res.abi) { - .msvc => "_msvc", - else => "_gnu", - }, - else => "", - }; - const target_name_slices = [_][:0]const u8{ "wgpu_", os_str, "_", arch_str, abi_str, "_", mode_str }; - const maybe_target_name = std.mem.concatWithSentinel(b.allocator, u8, &target_name_slices, 0); - const target_name = maybe_target_name catch |err| { - std.debug.panic("Failed to format target name: {s}", .{@errorName(err)}); - }; - - // Check if we have a dependency matching our selected target. - for (b.available_deps) |dep| { - const name, _ = dep; - if (std.mem.eql(u8, name, target_name)) { - break; - } - } else { - std.debug.panic("Could not find dependency matching target {s}", .{target_name}); - } - - const wgpu_mod = b.addModule("wgpu", .{ - .root_source_file = b.path("src/root.zig"), - .target = target, - .optimize = optimize, - .link_libcpp = true, - }); - - const wgpu_dep = b.lazyDependency(target_name, .{}) orelse return null; - - const translate_step = b.addTranslateC(.{ - // wgpu.h imports webgpu.h, so we get the contents of both files, as well as a bunch of libc garbage. - .root_source_file = wgpu_dep.path("include/webgpu/wgpu.h"), - - .target = target, - .optimize = optimize, - }); - - const wgpu_c_mod = translate_step.addModule("wgpu-c"); - wgpu_c_mod.resolved_target = target; - wgpu_c_mod.link_libcpp = true; - - var libwgpu_path: ?std.Build.LazyPath = null; - var is_windows: bool = false; - var is_mac: bool = target_res.os.tag == .macos or target_res.os.tag == .ios; - - // TODO: This seems like it could be made smaller, lots of repetitive code here. - switch (target_res.os.tag) { - .windows => { - is_windows = true; - if (target_res.abi == .msvc) { - // I feel like libcpp should work, but it definitely does not on msvc. Fortunately libc does. - wgpu_mod.link_libcpp = false; - wgpu_c_mod.link_libcpp = false; - wgpu_mod.link_libc = true; - wgpu_c_mod.link_libc = true; - - if (link_mode == .static) { - libwgpu_path = wgpu_dep.path("lib/wgpu_native.lib"); - - link_windows_system_libraries(std.Build.Module, wgpu_mod, false); - link_windows_system_libraries(std.Build.Module, wgpu_c_mod, false); - } else { - libwgpu_path = wgpu_dep.path("lib/wgpu_native.dll.lib"); - - // Unfortunately, it seems only the local tests can access the dll this way. - // For dependees, it copies to the zig cache, which you can use for testing if you do some weird stuff with the install steps, - // but it never copies to the output folder. So not helpful if you need to distribute a binary with the dll alongside it. - const dll_install_file = b.addInstallLibFile(wgpu_dep.path("lib/wgpu_native.dll"), "wgpu_native.dll"); - b.getInstallStep().dependOn(&dll_install_file.step); - - // For dependees that need the dll file, this seems to be the only reliable way to propagate it through. - // In Zig 0.14 there seems to be some method for exposing LazyPaths to dependees, which might be a bit cleaner. - const writeFiles = b.addNamedWriteFiles("lib"); - _ = writeFiles.addCopyFile(wgpu_dep.path("lib/wgpu_native.dll"), "wgpu_native.dll"); - } - } else { - if (link_mode == .static) { - libwgpu_path = wgpu_dep.path("lib/libwgpu_native.a"); - - link_windows_system_libraries(std.Build.Module, wgpu_mod, true); - link_windows_system_libraries(std.Build.Module, wgpu_c_mod, true); - } else { - libwgpu_path = wgpu_dep.path("lib/libwgpu_native.dll.a"); - - const dll_install_file = b.addInstallLibFile(wgpu_dep.path("lib/wgpu_native.dll"), "wgpu_native.dll"); - b.getInstallStep().dependOn(&dll_install_file.step); - - const writeFiles = b.addNamedWriteFiles("lib"); - _ = writeFiles.addCopyFile(wgpu_dep.path("lib/wgpu_native.dll"), "wgpu_native.dll"); - } - } - }, - - // This only tries to account for linux/macos since we're using pre-compiled wgpu-native; - // need to think harder about this if I get custom builds working. - else => if (link_mode == .static) { - libwgpu_path = wgpu_dep.path("lib/libwgpu_native.a"); - } else if (target_res.os.tag == .macos or target_res.os.tag == .ios) { // TODO: This is just guesswork, need to test it somehow, but I don't have a mac. - is_mac = true; - const dylib_install_file = b.addInstallLibFile(wgpu_dep.path("lib/libwgpu_native.dylib"), "libwgpu_native.dylib"); - b.getInstallStep().dependOn(&dylib_install_file.step); - - const writeFiles = b.addNamedWriteFiles("lib"); - _ = writeFiles.addCopyFile(wgpu_dep.path("lib/libwgpu_native.dylib"), "libwgpu_native.dylib"); - } else { - const so_install_file = b.addInstallLibFile(wgpu_dep.path("lib/libwgpu_native.so"), "libwgpu_native.so"); - b.getInstallStep().dependOn(&so_install_file.step); - - const writeFiles = b.addNamedWriteFiles("lib"); - _ = writeFiles.addCopyFile(wgpu_dep.path("lib/libwgpu_native.so"), "libwgpu_native.so"); - }, - } - - if (libwgpu_path != null) { - wgpu_mod.addObjectFile(libwgpu_path.?); - wgpu_c_mod.addObjectFile(libwgpu_path.?); - } - - return WGPUBuildContext{ - .link_mode = link_mode, - .target = target, - .optimize = optimize, - .is_windows = is_windows, - .is_mac = is_mac, - .wgpu_dep = wgpu_dep, - .libwgpu_path = libwgpu_path, - .install_lib_dir = b.getInstallPath(.lib, ""), - .wgpu_mod = wgpu_mod, - .wgpu_c_mod = wgpu_c_mod, - }; - } -}; - -fn dynamic_link(context: *const WGPUBuildContext, c: *std.Build.Step.Compile, cmd: *std.Build.Step.Run) void { - if (!context.is_windows) { - c.addLibraryPath(context.wgpu_dep.path("lib")); - c.linkSystemLibrary2("wgpu_native", .{}); - } - cmd.addPathDir(context.install_lib_dir); +pub fn link_mac_frameworks(mod: *std.Build.Module) void { + mod.linkFramework("Foundation", .{}); + mod.linkFramework("QuartzCore", .{}); + mod.linkFramework("Metal", .{}); } -fn handle_rt(context: *const WGPUBuildContext, exe: *std.Build.Step.Compile) void { - if (context.is_windows and context.target.result.abi == .msvc) { +pub fn disable_rt_for_msvc(exe: *std.Build.Step.Compile) void { + const target = exe.rootModuleTarget(); + if (target.os.tag == .windows and target.abi == .msvc) { // We get duplicate symbol errors at link-time if we don't disable these; exe.bundle_compiler_rt = false; exe.bundle_ubsan_rt = false; } } +fn quick_link(t: *std.Build.Step.Compile, link_mode: std.builtin.LinkMode, lp: std.Build.LazyPath) void { + if (link_mode == .dynamic) { + // normally here you would add a build step to copy all your shared libraries to + // a specific folder for distribution + // you would tell the executable to where to find the executable the shared library with + // exe.addRPath(...); + + // this is just quick and dirty to test the thing + t.addObjectFile(lp); + t.addRPath(lp.dirname()); + } + // (nat3): cant test this since i am a mac user + disable_rt_for_msvc(t); +} -fn triangle_example(b: *std.Build, context: *const WGPUBuildContext) void { +fn triangle_example(b: *std.Build, wgpu_mod: *std.Build.Module, link_mode: std.builtin.LinkMode, lp: std.Build.LazyPath) *std.Build.Step { const bmp_mod = b.createModule(.{ .root_source_file = b.path("examples/bmp.zig"), }); - - const triangle_example_exe_mod = b.createModule(.{ - .root_source_file = b.path("examples/triangle/triangle.zig"), - .target = context.target, - .optimize = context.optimize, - }); - triangle_example_exe_mod.addImport("wgpu", context.wgpu_mod); - triangle_example_exe_mod.addImport("bmp", bmp_mod); const triangle_example_exe = b.addExecutable(.{ .name = "triangle-example", - .root_module = triangle_example_exe_mod, + .root_source_file = b.path("examples/triangle/triangle.zig"), + .target = wgpu_mod.resolved_target, + .optimize = wgpu_mod.optimize.?, }); - handle_rt(context, triangle_example_exe); - + triangle_example_exe.root_module.addImport("wgpu", wgpu_mod); + triangle_example_exe.root_module.addImport("bmp", bmp_mod); const run_triangle_cmd = b.addRunArtifact(triangle_example_exe); - const run_triangle_step = b.step("run-triangle-example", "Run the triangle example"); run_triangle_step.dependOn(&run_triangle_cmd.step); - - if (context.link_mode == .dynamic) { - dynamic_link(context, triangle_example_exe, run_triangle_cmd); - - run_triangle_cmd.step.dependOn(b.getInstallStep()); - } + quick_link(triangle_example_exe, link_mode, lp); + return run_triangle_step; } -fn unit_tests(b: *std.Build, context: *const WGPUBuildContext) void { +fn unit_tests(b: *std.Build, wgpu_mod: *std.Build.Module, link_mode: std.builtin.LinkMode, lp: std.Build.LazyPath) *std.Build.Step { const unit_test_step = b.step("test", "Run unit tests"); - if (context.is_windows) { - unit_test_step.dependOn(b.getInstallStep()); - } - const test_files = [_][:0]const u8{ "src/instance.zig", "src/adapter.zig", @@ -278,106 +100,170 @@ fn unit_tests(b: *std.Build, context: *const WGPUBuildContext) void { const test_name = test_file[4..(test_file.len - 4)] ++ "-test"; test_names[idx] = test_name; }; - for (test_files, test_names) |test_file, test_name| { - // TODO: Seems weird to have a mod for each unit test, should probably revisit this. - const test_mod = b.createModule(.{ - .root_source_file = b.path(test_file), - .target = context.target, - .optimize = context.optimize, - }); const t = b.addTest(.{ .name = test_name, - .root_module = test_mod, + .root_source_file = b.path(test_file), + .target = wgpu_mod.resolved_target, + .optimize = wgpu_mod.optimize.?, }); - handle_rt(context, t); - if (context.libwgpu_path != null) { - t.addObjectFile(context.libwgpu_path.?); - } - if (context.is_windows) { - t.linkLibC(); - } else { - t.linkLibCpp(); - } - + t.root_module.addImport("wgpu", wgpu_mod); + // handle_rt(context, t); const run_test = b.addRunArtifact(t); - - if (context.is_mac) { - link_mac_frameworks(t); - } - - if (context.link_mode == .dynamic) { - dynamic_link(context, t, run_test); - } else if (context.is_windows) { - if (context.target.result.abi == .gnu) { - link_windows_system_libraries(std.Build.Step.Compile, t, true); - - // TODO: Find out why this is only required here; seems suspicious - t.linkSystemLibrary2("unwind", .{}); - } else { - link_windows_system_libraries(std.Build.Step.Compile, t, false); - } - } - unit_test_step.dependOn(&run_test.step); + quick_link(t, link_mode, lp); } + return unit_test_step; } -fn compute_tests(b: *std.Build, context: *const WGPUBuildContext) void { - const compute_test_mod = b.createModule(.{ - .root_source_file = b.path("tests/compute.zig"), - .target = context.target, - .optimize = context.optimize, - }); - compute_test_mod.addImport("wgpu", context.wgpu_mod); +fn compute_tests(b: *std.Build, wgpu_mod: *std.Build.Module, wgpu_c_mod: *std.Build.Module, link_mode: std.builtin.LinkMode, lp: std.Build.LazyPath) *std.Build.Step { + const compute_test_step = b.step("compute-tests", "Run compute shader tests"); + const compute_test = b.addTest(.{ .name = "compute-test", - .root_module = compute_test_mod, + .root_source_file = b.path("tests/compute.zig"), + .target = wgpu_mod.resolved_target, + .optimize = wgpu_mod.optimize.?, }); - handle_rt(context, compute_test); - + compute_test.root_module.addImport("wgpu", wgpu_mod); + // handle_rt(context, compute_test); const run_compute_test = b.addRunArtifact(compute_test); + compute_test_step.dependOn(&run_compute_test.step); - const compute_test_c_mod = b.createModule(.{ - .root_source_file = b.path("tests/compute_c.zig"), - .target = context.target, - .optimize = context.optimize, - }); - compute_test_c_mod.addImport("wgpu-c", context.wgpu_c_mod); const compute_test_c = b.addTest(.{ .name = "compute-test-c", - .root_module = compute_test_c_mod, + .root_source_file = b.path("tests/compute_c.zig"), + .target = wgpu_mod.resolved_target, + .optimize = wgpu_mod.optimize.?, }); - handle_rt(context, compute_test_c); - + compute_test_c.root_module.addImport("wgpu-c", wgpu_c_mod); + // handle_rt(context, compute_test_c); const run_compute_test_c = b.addRunArtifact(compute_test_c); - - const compute_test_step = b.step("compute-tests", "Run compute shader tests"); - if (context.link_mode == .dynamic) { - dynamic_link(context, compute_test, run_compute_test); - dynamic_link(context, compute_test_c, run_compute_test_c); - - run_compute_test.step.dependOn(b.getInstallStep()); - run_compute_test_c.step.dependOn(b.getInstallStep()); - } - - if (context.is_mac) { - link_mac_frameworks(compute_test); - link_mac_frameworks(compute_test_c); - } - - compute_test_step.dependOn(&run_compute_test.step); compute_test_step.dependOn(&run_compute_test_c.step); + + quick_link(compute_test, link_mode, lp); + quick_link(compute_test_c, link_mode, lp); + return compute_test_step; } // Although this function looks imperative, note that its job is to // declaratively construct a build graph that will be executed by an external // runner. pub fn build(b: *std.Build) void { - const context = WGPUBuildContext.init(b) orelse return; + const link_mode = b.option(std.builtin.LinkMode, "link_mode", "Use static linking instead of dynamic linking.") orelse .static; + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const wgpu_dep = get_wgpu_dep(b, target, optimize); + const translate_step = b.addTranslateC(.{ + // wgpu.h imports webgpu.h, so we get the contents of both files, as well as a bunch of libc garbage. + .root_source_file = wgpu_dep.path("include/webgpu/wgpu.h"), + .target = target, + .optimize = optimize, + }); + const wgpu_c_mod = translate_step.addModule("wgpu-c"); + + const wgpu_mod = b.addModule("wgpu", .{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); - compute_tests(b, &context); - unit_tests(b, &context); + if (target.result.abi != .msvc) { + wgpu_c_mod.link_libcpp = true; + wgpu_mod.link_libcpp = true; + } + switch (target.result.os.tag) { + .windows => { + link_windows_system_libraries(std.Build.Module, wgpu_mod, true); + link_windows_system_libraries(std.Build.Module, wgpu_c_mod, true); + }, + .macos, .ios => { + link_mac_frameworks(wgpu_mod); + link_mac_frameworks(wgpu_c_mod); + }, + else => {}, + } + // this is the lazy path to the .dll / .dylib / .so + // its added for users of this module dependency under the name "lib" + // you can get it with `.namedLazyPath("libwgpu_native")` + + const extension: []const u8 = + if (link_mode == .static) + switch (target.result.os.tag) { + .windows => "lib", + else => "a", + } + else switch (target.result.os.tag) { + .windows => "dll", + .macos, .ios => "dylib", + else => "so", + }; + // NOTE: on windows the objects from rust dont have the "lib" prefix! + const prefix = switch (target.result.os.tag) { + .windows => "", + else => "lib", + }; + const lib_name = b.fmt("lib/{s}wgpu_native.{s}", .{ prefix, extension }); - triangle_example(b, &context); + const wgpu_native_lib = wgpu_dep.path(lib_name); + + if (link_mode == .static) { + wgpu_mod.addObjectFile(wgpu_native_lib); + wgpu_c_mod.addObjectFile(wgpu_native_lib); + } else { + b.addNamedLazyPath("libwgpu_native", wgpu_native_lib); + } + const compute_tests_step = compute_tests(b, wgpu_mod, wgpu_c_mod, link_mode, wgpu_native_lib); + const unit_tests_step = unit_tests(b, wgpu_mod, link_mode, wgpu_native_lib); + const triangle_example_step = triangle_example(b, wgpu_mod, link_mode, wgpu_native_lib); + + const step_all = b.step("all", "run everything"); + step_all.dependOn(compute_tests_step); + step_all.dependOn(unit_tests_step); + step_all.dependOn(triangle_example_step); +} + +pub fn get_wgpu_dep(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Dependency { + const target_res = target.result; + const os_str = @tagName(target_res.os.tag); + const arch_str = @tagName(target_res.cpu.arch); + + const mode_str = switch (optimize) { + .Debug => "debug", + else => "release", + }; + const abi_str = switch (target_res.os.tag) { + .ios => switch (target_res.abi) { + .simulator => "_simulator", + else => "", + }, + .windows => switch (target_res.abi) { + .msvc => "_msvc", + else => "_gnu", + }, + else => "", + }; + const target_name_slices = [_][:0]const u8{ "wgpu_", os_str, "_", arch_str, abi_str, "_", mode_str }; + const maybe_target_name = std.mem.concatWithSentinel(b.allocator, u8, &target_name_slices, 0); + const target_name = maybe_target_name catch |err| { + std.debug.panic("Failed to format target name: {s}", .{@errorName(err)}); + }; + // Check if we have a dependency matching our selected target. + for (b.available_deps) |dep| { + const name, _ = dep; + if (std.mem.eql(u8, name, target_name)) { + break; + } + } else { + std.debug.panic("Could not find dependency matching target {s}", .{target_name}); + } + return b.lazyDependency(target_name, .{}) orelse unreachable; } diff --git a/examples/bmp.zig b/examples/bmp.zig index ddc1b65..152c03a 100644 --- a/examples/bmp.zig +++ b/examples/bmp.zig @@ -7,10 +7,10 @@ pub fn write24BitBMP(file_name: []const u8, comptime width: u32, comptime height var writer = file.writer(); // ID - _ = try writer.write(&[2]u8{'B', 'M'}); + _ = try writer.write(&[2]u8{ 'B', 'M' }); const colors_per_line = width * 3; - const bytes_per_line = switch(colors_per_line & 0x00000003) { + const bytes_per_line = switch (colors_per_line & 0x00000003) { 0 => colors_per_line, else => (colors_per_line | 0x00000003) + 1, }; @@ -45,8 +45,8 @@ pub fn write24BitBMP(file_name: []const u8, comptime width: u32, comptime height const bgra_pixel_offset = line_offset + (x * 4); line_buffer[bgr_pixel_offset] = bgra_data[bgra_pixel_offset]; line_buffer[bgr_pixel_offset + 1] = bgra_data[bgra_pixel_offset + 1]; - line_buffer[bgr_pixel_offset + 2] = bgra_data[bgra_pixel_offset + 2]; + line_buffer[bgr_pixel_offset + 2] = bgra_data[bgra_pixel_offset + 2]; } _ = try writer.write(&line_buffer); } -} \ No newline at end of file +} diff --git a/examples/output/.gitkeep b/examples/output/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/examples/triangle/triangle.zig b/examples/triangle/triangle.zig index f0fbf25..0f7884d 100644 --- a/examples/triangle/triangle.zig +++ b/examples/triangle/triangle.zig @@ -2,7 +2,7 @@ const std = @import("std"); const wgpu = @import("wgpu"); const bmp = @import("bmp"); -const output_extent = wgpu.Extent3D { +const output_extent = wgpu.Extent3D{ .width = 640, .height = 480, .depth_or_array_layers = 1, @@ -22,17 +22,17 @@ pub fn main() !void { const instance = wgpu.Instance.create(null).?; defer instance.release(); - const adapter_request = instance.requestAdapterSync(&wgpu.RequestAdapterOptions {}, 0); - const adapter = switch(adapter_request.status) { + const adapter_request = instance.requestAdapterSync(&wgpu.RequestAdapterOptions{}, 0); + const adapter = switch (adapter_request.status) { .success => adapter_request.adapter.?, else => return error.NoAdapter, }; defer adapter.release(); - const device_request = adapter.requestDeviceSync(instance, &wgpu.DeviceDescriptor { + const device_request = adapter.requestDeviceSync(instance, &wgpu.DeviceDescriptor{ .required_limits = null, }, 0); - const device = switch(device_request.status) { + const device = switch (device_request.status) { .success => device_request.device.?, else => return error.NoDevice, }; @@ -43,7 +43,7 @@ pub fn main() !void { const swap_chain_format = wgpu.TextureFormat.bgra8_unorm_srgb; - const target_texture = device.createTexture(&wgpu.TextureDescriptor { + const target_texture = device.createTexture(&wgpu.TextureDescriptor{ .label = wgpu.StringView.fromSlice("Render texture"), .size = output_extent, .format = swap_chain_format, @@ -51,7 +51,7 @@ pub fn main() !void { }).?; defer target_texture.release(); - const target_texture_view = target_texture.createView(&wgpu.TextureViewDescriptor { + const target_texture_view = target_texture.createView(&wgpu.TextureViewDescriptor{ .label = wgpu.StringView.fromSlice("Render texture view"), .mip_level_count = 1, .array_layer_count = 1, @@ -62,7 +62,7 @@ pub fn main() !void { })).?; defer shader_module.release(); - const staging_buffer = device.createBuffer(&wgpu.BufferDescriptor { + const staging_buffer = device.createBuffer(&wgpu.BufferDescriptor{ .label = wgpu.StringView.fromSlice("staging_buffer"), .usage = wgpu.BufferUsages.map_read | wgpu.BufferUsages.copy_dst, .size = output_size, @@ -70,16 +70,16 @@ pub fn main() !void { }).?; defer staging_buffer.release(); - const color_targets = &[_] wgpu.ColorTargetState{ - wgpu.ColorTargetState { + const color_targets = &[_]wgpu.ColorTargetState{ + wgpu.ColorTargetState{ .format = swap_chain_format, - .blend = &wgpu.BlendState { - .color = wgpu.BlendComponent { + .blend = &wgpu.BlendState{ + .color = wgpu.BlendComponent{ .operation = .add, .src_factor = .src_alpha, .dst_factor = .one_minus_src_alpha, }, - .alpha = wgpu.BlendComponent { + .alpha = wgpu.BlendComponent{ .operation = .add, .src_factor = .zero, .dst_factor = .one, @@ -88,37 +88,30 @@ pub fn main() !void { }, }; - const pipeline = device.createRenderPipeline(&wgpu.RenderPipelineDescriptor { - .vertex = wgpu.VertexState { + const pipeline = device.createRenderPipeline(&wgpu.RenderPipelineDescriptor{ + .vertex = wgpu.VertexState{ .module = shader_module, .entry_point = wgpu.StringView.fromSlice("vs_main"), }, - .primitive = wgpu.PrimitiveState {}, - .fragment = &wgpu.FragmentState { - .module = shader_module, - .entry_point = wgpu.StringView.fromSlice("fs_main"), - .target_count = color_targets.len, - .targets = color_targets.ptr - }, - .multisample = wgpu.MultisampleState {}, + .primitive = wgpu.PrimitiveState{}, + .fragment = &wgpu.FragmentState{ .module = shader_module, .entry_point = wgpu.StringView.fromSlice("fs_main"), .target_count = color_targets.len, .targets = color_targets.ptr }, + .multisample = wgpu.MultisampleState{}, }).?; defer pipeline.release(); { // Mock main "loop" const next_texture = target_texture_view; - const encoder = device.createCommandEncoder(&wgpu.CommandEncoderDescriptor { + const encoder = device.createCommandEncoder(&wgpu.CommandEncoderDescriptor{ .label = wgpu.StringView.fromSlice("Command Encoder"), }).?; defer encoder.release(); - const color_attachments = &[_]wgpu.ColorAttachment{ - wgpu.ColorAttachment { - .view = next_texture, - .clear_value = wgpu.Color {}, - } - }; - const render_pass = encoder.beginRenderPass(&wgpu.RenderPassDescriptor { + const color_attachments = &[_]wgpu.ColorAttachment{wgpu.ColorAttachment{ + .view = next_texture, + .clear_value = wgpu.Color{}, + }}; + const render_pass = encoder.beginRenderPass(&wgpu.RenderPassDescriptor{ .color_attachment_count = color_attachments.len, .color_attachments = color_attachments.ptr, }).?; @@ -133,12 +126,12 @@ pub fn main() !void { defer next_texture.release(); - const img_copy_src = wgpu.TexelCopyTextureInfo { - .origin = wgpu.Origin3D {}, + const img_copy_src = wgpu.TexelCopyTextureInfo{ + .origin = wgpu.Origin3D{}, .texture = target_texture, }; - const img_copy_dst = wgpu.TexelCopyBufferInfo { - .layout = wgpu.TexelCopyBufferLayout { + const img_copy_dst = wgpu.TexelCopyBufferInfo{ + .layout = wgpu.TexelCopyBufferLayout{ .bytes_per_row = output_bytes_per_row, .rows_per_image = output_extent.height, }, @@ -147,7 +140,7 @@ pub fn main() !void { encoder.copyTextureToBuffer(&img_copy_src, &img_copy_dst, &output_extent); - const command_buffer = encoder.finish(&wgpu.CommandBufferDescriptor { + const command_buffer = encoder.finish(&wgpu.CommandBufferDescriptor{ .label = wgpu.StringView.fromSlice("Command Buffer"), }).?; defer command_buffer.release(); @@ -155,12 +148,12 @@ pub fn main() !void { queue.submit(&[_]*const wgpu.CommandBuffer{command_buffer}); var buffer_map_complete = false; - _ = staging_buffer.mapAsync(wgpu.MapModes.read, 0, output_size, wgpu.BufferMapCallbackInfo { + _ = staging_buffer.mapAsync(wgpu.MapModes.read, 0, output_size, wgpu.BufferMapCallbackInfo{ .callback = handleBufferMap, .userdata1 = @ptrCast(&buffer_map_complete), }); instance.processEvents(); - while(!buffer_map_complete) { + while (!buffer_map_complete) { instance.processEvents(); } // _ = device.poll(true, null); @@ -169,6 +162,7 @@ pub fn main() !void { defer staging_buffer.unmap(); const output = buf[0..output_size]; + try std.fs.cwd().makePath("examples/output"); try bmp.write24BitBMP("examples/output/triangle.bmp", output_extent.width, output_extent.height, output); } -} \ No newline at end of file +}