commit f3cef556477a90786fbeca7f431c74ecc9d65ac8 Author: David Allemang Date: Wed May 27 16:02:01 2026 -0400 wip initial testing diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2262044 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea/ +.zig-cache/ +zig-out/ +zig-pkg/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..3e58c65 --- /dev/null +++ b/build.zig @@ -0,0 +1,74 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const vk_dep = b.dependency("vk", .{}); + const volk_dep = b.dependency("volk", .{}); + + // const volk_c = b.addTranslateC(.{ + // .target = target, + // .optimize = optimize, + // .root_source_file = volk_dep.path("volk.c"), + // .link_libc = true, + // }); + // volk_c.addIncludePath(vk_dep.path("include")); + + const vk = b.addModule("vulkan", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/volk.zig"), + .link_libc = true, + }); + vk.addIncludePath(vk_dep.path("include")); + vk.addIncludePath(volk_dep.path(".")); + vk.addCSourceFile(.{ .file = volk_dep.path("volk.c"), .language = .c }); + + const mod = b.addModule("zig_vk_api_test", .{ + .root_source_file = b.path("src/root.zig"), + .target = target, + }); + + const exe = b.addExecutable(.{ + .name = "zig_vk_api_test", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "zig_vk_api_test", .module = mod }, + .{ .name = "vk", .module = vk }, + }, + }), + }); + + b.installArtifact(exe); + + const run_step = b.step("run", "Run the app"); + + const run_cmd = b.addRunArtifact(exe); + run_step.dependOn(&run_cmd.step); + + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const mod_tests = b.addTest(.{ + .root_module = mod, + }); + + const run_mod_tests = b.addRunArtifact(mod_tests); + + const exe_tests = b.addTest(.{ + .root_module = exe.root_module, + }); + + const run_exe_tests = b.addRunArtifact(exe_tests); + + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&run_mod_tests.step); + test_step.dependOn(&run_exe_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..f20545a --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,21 @@ +.{ + .name = .zig_vk_api_test, + .version = "0.0.0", + .fingerprint = 0xa7b5f349ba365910, + .minimum_zig_version = "0.16.0", + .dependencies = .{ + .vk = .{ + .url = "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v1.4.352.tar.gz", + .hash = "N-V-__8AAHAZeALsJNAOsFHuMyyXDuoFVG48EQdnJGNAZ3Th", + }, + .volk = .{ + .url = "https://github.com/zeux/volk/archive/refs/tags/1.4.350.tar.gz", + .hash = "N-V-__8AAFGqCADosOofL302vYn3DZNlkeErvJevsqMt-Jpa", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..abdd0f3 --- /dev/null +++ b/mise.toml @@ -0,0 +1,3 @@ +[tools] +zig = "latest" +zls = "latest" diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..93a7a53 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,132 @@ +const std = @import("std"); +const Io = std.Io; + +const vk = @import("vk"); + +pub fn main() !void { + if (vk.c.volkInitialize() != vk.c.VK_SUCCESS) @panic("Failed to initialize vk"); + defer vk.c.volkFinalize(); + + const app_info = vk.c.VkApplicationInfo{ + .sType = vk.c.VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = null, + .apiVersion = vk.c.VK_API_VERSION_1_4, + .pApplicationName = "WIP", + .applicationVersion = vk.c.VK_MAKE_VERSION(0, 0, 1), + .pEngineName = "WIP", + .engineVersion = vk.c.VK_MAKE_VERSION(0, 0, 1), + }; + + const ext_names: []const [*c]const u8 = &.{"VK_EXT_debug_utils"}; + const lyr_names: []const [*c]const u8 = &.{"VK_LAYER_KHRONOS_validation"}; + + const ins_info = vk.c.VkInstanceCreateInfo{ + .sType = vk.c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = null, + .flags = 0, + .enabledExtensionCount = @intCast(ext_names.len), + .ppEnabledExtensionNames = ext_names.ptr, + .enabledLayerCount = @intCast(lyr_names.len), + .ppEnabledLayerNames = lyr_names.ptr, + .pApplicationInfo = &app_info, + }; + const deb_info = vk.c.VkDebugUtilsMessengerCreateInfoEXT{ + .sType = vk.c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = null, + .flags = 0, + }; + + var ins: vk.c.VkInstance = undefined; + if (vk.c.vkCreateInstance.?(&ins_info, null, &ins) != vk.c.VK_SUCCESS) @panic("Failed to create VkInstance"); + vk.c.volkLoadInstanceOnly(ins); + defer vk.c.vkDestroyInstance.?(ins, null); + + var pdevs: [3]vk.c.VkPhysicalDevice = undefined; + var pdev_count: u32 = 3; + if (vk.c.vkEnumeratePhysicalDevices.?( + ins, + &pdev_count, + &pdevs, + ) != vk.c.VK_SUCCESS) @panic("Failed to enumerate physical devices."); + + // pub const PFN_vkEnumeratePhysicalDevices = ?*const fn (instance: VkInstance, pPhysicalDeviceCount: [*c]u32, pPhysicalDevices: [*c]VkPhysicalDevice) callconv(.c) VkResult; + + // vk.c.vkEnumerateDeviceExtensionProperties(); + + // const info = vk.c.VkInstanceCreateInfo { + // .sType = vk.c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + // .pNext = null, + // . + // }; + + // vk.c.vkCreateInstance(pCreateInfo: [*c]const VkInstanceCreateInfo, pAllocator: [*c]const VkAllocationCallbacks, pInstance: [*c]VkInstance); +} + +// pub fn main(init: std.process.Init) !void { +// std.debug.print("{any}\n", .{vk}); +// +// // Prints to stderr, unbuffered, ignoring potential errors. +// std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); +// +// // This is appropriate for anything that lives as long as the process. +// const arena: std.mem.Allocator = init.arena.allocator(); +// +// // Accessing command line arguments: +// const args = try init.minimal.args.toSlice(arena); +// for (args) |arg| { +// std.log.info("arg: {s}", .{arg}); +// } +// +// // In order to do I/O operations need an `Io` instance. +// const io = init.io; +// +// // Stdout is for the actual output of your application, for example if you +// // are implementing gzip, then only the compressed bytes should be sent to +// // stdout, not any debugging messages. +// var stdout_buffer: [1024]u8 = undefined; +// var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); +// const stdout_writer = &stdout_file_writer.interface; +// +// try zig_vk_api_test.printAnotherMessage(stdout_writer); +// +// try stdout_writer.flush(); // Don't forget to flush! +// } +// +// test "simple test" { +// const gpa = std.testing.allocator; +// var list: std.ArrayList(i32) = .empty; +// defer list.deinit(gpa); // Try commenting this out and see if zig detects the memory leak! +// try list.append(gpa, 42); +// try std.testing.expectEqual(@as(i32, 42), list.pop()); +// } +// +// test "fuzz example" { +// try std.testing.fuzz({}, testOne, .{}); +// } +// +// fn testOne(context: void, smith: *std.testing.Smith) !void { +// _ = context; +// // Try passing `--fuzz` to `zig build test` and see if it manages to fail this test case! +// +// const gpa = std.testing.allocator; +// var list: std.ArrayList(u8) = .empty; +// defer list.deinit(gpa); +// while (!smith.eos()) switch (smith.value(enum { add_data, dup_data })) { +// .add_data => { +// const slice = try list.addManyAsSlice(gpa, smith.value(u4)); +// smith.bytes(slice); +// }, +// .dup_data => { +// if (list.items.len == 0) continue; +// if (list.items.len > std.math.maxInt(u32)) return error.SkipZigTest; +// const len = smith.valueRangeAtMost(u32, 1, @min(32, list.items.len)); +// const off = smith.valueRangeAtMost(u32, 0, @intCast(list.items.len - len)); +// try list.appendSlice(gpa, list.items[off..][0..len]); +// try std.testing.expectEqualSlices( +// u8, +// list.items[off..][0..len], +// list.items[list.items.len - len ..], +// ); +// }, +// }; +// } diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..5a71250 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,18 @@ +//! By convention, root.zig is the root source file when making a package. +const std = @import("std"); +const Io = std.Io; + +/// This is a documentation comment to explain the `printAnotherMessage` function below. +/// +/// Accepting an `Io.Writer` instance is a handy way to write reusable code. +pub fn printAnotherMessage(writer: *Io.Writer) Io.Writer.Error!void { + try writer.print("Run `zig build test` to run the tests.\n", .{}); +} + +pub fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + try std.testing.expect(add(3, 7) == 10); +} diff --git a/src/volk.zig b/src/volk.zig new file mode 100644 index 0000000..f372e55 --- /dev/null +++ b/src/volk.zig @@ -0,0 +1,25 @@ +const std = @import("std"); + +pub const c = @cImport({ + @cInclude("volk.h"); +}); + +pub const InstanceTable = blk: { + const info = @typeInfo(c.VolkInstanceTable).@"struct"; + + var field_names: [info.fields.len][]const u8 = undefined; + var field_types: [info.fields.len]type = undefined; + var field_attrs: [info.fields.len]std.builtin.Type.StructField.Attributes = undefined; + + for (info.fields, &field_names, &field_types, &field_attrs) |field, *field_name, *field_type, *field_attr| { + field_name.* = field.name; + field_type.* = std.meta.Child(field.type); + field_attr.* = .{}; + } + + break :blk @Struct(.auto, null, field_names, field_types, field_attrs); +}; + +// pub const InstanceTable: type = { +// +// };