From c3c9333d73801e3ab1544379fda3eb87765c9d0f Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 11:26:44 +0200 Subject: [PATCH 1/7] Remove zig.mod Seems this is not really relevant anymore with the new build system --- zig.mod | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 zig.mod diff --git a/zig.mod b/zig.mod deleted file mode 100644 index 2d3302b..0000000 --- a/zig.mod +++ /dev/null @@ -1,6 +0,0 @@ -id: uxw7q1ovyv4z3t7fi28agxovmhbrobglw7mwtl5p3pnsc1gu -name: vulkan-zig -main: generator/index.zig -license: MIT -description: Vulkan binding generator for Zig -dependencies: From e1f290399e1bcc37fd24a93e24583b2c1284cf1a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 11:27:49 +0200 Subject: [PATCH 2/7] move generator/ to src/ A long time ago there was the idea to use src/ for something else, but that is no longer relevant. Its nice to switch to a more conventional repo layout. --- README.md | 2 +- build.zig | 6 +++--- {generator => src}/build_integration.zig | 0 {generator => src}/id_render.zig | 0 {generator => src}/index.zig | 0 {generator => src}/main.zig | 0 {generator => src}/vulkan/build_integration.zig | 0 {generator => src}/vulkan/c_parse.zig | 0 {generator => src}/vulkan/generator.zig | 0 {generator => src}/vulkan/parse.zig | 0 {generator => src}/vulkan/registry.zig | 0 {generator => src}/vulkan/render.zig | 0 {generator => src}/xml.zig | 0 13 files changed, 4 insertions(+), 4 deletions(-) rename {generator => src}/build_integration.zig (100%) rename {generator => src}/id_render.zig (100%) rename {generator => src}/index.zig (100%) rename {generator => src}/main.zig (100%) rename {generator => src}/vulkan/build_integration.zig (100%) rename {generator => src}/vulkan/c_parse.zig (100%) rename {generator => src}/vulkan/generator.zig (100%) rename {generator => src}/vulkan/parse.zig (100%) rename {generator => src}/vulkan/registry.zig (100%) rename {generator => src}/vulkan/render.zig (100%) rename {generator => src}/xml.zig (100%) diff --git a/README.md b/README.md index 523cae6..4a5874d 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ NOTE: you need to replace `path/to/vk.xml` with the spec path from whatever sour ### Generation from build.zig Vulkan bindings can be generated from the Vulkan XML registry at compile time with build.zig, by using the provided Vulkan generation step: ```zig -const vkgen = @import("vulkan-zig/generator/index.zig"); +const vkgen = @import("vulkan-zig/src/index.zig"); pub fn build(b: *Builder) void { ... diff --git a/build.zig b/build.zig index 6a1c7c6..1433e56 100644 --- a/build.zig +++ b/build.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const vkgen = @import("generator/index.zig"); +const vkgen = @import("src/index.zig"); pub const ShaderCompileStep = vkgen.ShaderCompileStep; pub const VkGenerateStep = vkgen.VkGenerateStep; @@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void { // a file source to the generated code with `.addOutputArg("vk.zig")` const generator_exe = b.addExecutable(.{ .name = "generator", - .root_source_file = .{ .path = "generator/main.zig" }, + .root_source_file = .{ .path = "src/main.zig" }, .target = target, .optimize = optimize, }); @@ -69,7 +69,7 @@ pub fn build(b: *std.Build) void { triangle_run_step.dependOn(&triangle_run_cmd.step); const test_target = b.addTest(.{ - .root_source_file = .{ .path = "generator/index.zig" }, + .root_source_file = .{ .path = "src/index.zig" }, }); const run_test = b.addRunArtifact(test_target); diff --git a/generator/build_integration.zig b/src/build_integration.zig similarity index 100% rename from generator/build_integration.zig rename to src/build_integration.zig diff --git a/generator/id_render.zig b/src/id_render.zig similarity index 100% rename from generator/id_render.zig rename to src/id_render.zig diff --git a/generator/index.zig b/src/index.zig similarity index 100% rename from generator/index.zig rename to src/index.zig diff --git a/generator/main.zig b/src/main.zig similarity index 100% rename from generator/main.zig rename to src/main.zig diff --git a/generator/vulkan/build_integration.zig b/src/vulkan/build_integration.zig similarity index 100% rename from generator/vulkan/build_integration.zig rename to src/vulkan/build_integration.zig diff --git a/generator/vulkan/c_parse.zig b/src/vulkan/c_parse.zig similarity index 100% rename from generator/vulkan/c_parse.zig rename to src/vulkan/c_parse.zig diff --git a/generator/vulkan/generator.zig b/src/vulkan/generator.zig similarity index 100% rename from generator/vulkan/generator.zig rename to src/vulkan/generator.zig diff --git a/generator/vulkan/parse.zig b/src/vulkan/parse.zig similarity index 100% rename from generator/vulkan/parse.zig rename to src/vulkan/parse.zig diff --git a/generator/vulkan/registry.zig b/src/vulkan/registry.zig similarity index 100% rename from generator/vulkan/registry.zig rename to src/vulkan/registry.zig diff --git a/generator/vulkan/render.zig b/src/vulkan/render.zig similarity index 100% rename from generator/vulkan/render.zig rename to src/vulkan/render.zig diff --git a/generator/xml.zig b/src/xml.zig similarity index 100% rename from generator/xml.zig rename to src/xml.zig From c5725dfb2e32dd463e02b4ca239de5ad74437b64 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 11:33:58 +0200 Subject: [PATCH 3/7] rename 'generator' binary to 'vulkan-zig-generator' This changes the name of the generator binary from something very generic to something a little more descriptive. If using the package manager method to use the generator, this will require updating to the new name. --- README.md | 4 ++-- build.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4a5874d..33065b2 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ vulkan-zig aims to be always compatible with the ever-changing Zig master branch ### CLI-interface A CLI-interface is provided to generate vk.zig from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/main/xml), which is built by default when invoking `zig build` in the project root. To generate vk.zig, simply invoke the program as follows: ``` -$ zig-out/bin/generator path/to/vk.xml output/path/to/vk.zig +$ zig-out/bin/vulkan-zig-generator path/to/vk.xml output/path/to/vk.zig ``` This reads the xml file, parses its contents, renders the Vulkan bindings, and formats file, before writing the result to the output path. While the intended usage of vulkan-zig is through direct generation from build.zig (see below), the CLI-interface can be used for one-off generation and vendoring the result. NOTE: you need to replace `path/to/vk.xml` with the spec path from whatever source you prefer, here are some examples orderered from the most recommended: @@ -77,7 +77,7 @@ That will allow you to `@import("vulkan-zig")` in your executable's source. In the event you have a specific need for it, the generator executable is made available through the dependency, allowing you to run the executable as a build step in your own build.zig file. Doing so should look a bit like this: ```zig -const vk_gen = b.dependency("vulkan_zig", .{}).artifact("generator"); // get generator executable reference +const vk_gen = b.dependency("vulkan_zig", .{}).artifact("vulkan-zig-generator"); // get generator executable reference const generate_cmd = b.addRunArtifact(vk_gen); generate_cmd.addArg(b.pathFromRoot("vk.xml")); // path to xml file to use when generating the bindings diff --git a/build.zig b/build.zig index 1433e56..3ee2219 100644 --- a/build.zig +++ b/build.zig @@ -10,11 +10,11 @@ pub fn build(b: *std.Build) void { const vk_xml_path: ?[]const u8 = b.option([]const u8, "registry", "Override the path to the Vulkan registry"); // using the package manager, this artifact can be obtained by the user - // through `b.dependency(, .{}).artifact("generator")`. + // through `b.dependency(, .{}).artifact("vulkan-zig-generator")`. // with that, the user need only `.addArg("path/to/vk.xml")`, and then obtain // a file source to the generated code with `.addOutputArg("vk.zig")` const generator_exe = b.addExecutable(.{ - .name = "generator", + .name = "vulkan-zig-generator", .root_source_file = .{ .path = "src/main.zig" }, .target = target, .optimize = optimize, From 1fdb930ae36242a530d4e4842799a9add2af6194 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 12:01:09 +0200 Subject: [PATCH 4/7] build example using tool instead of custom step We are about to get rid of the custom build steps, so build the example in a similar way that the downstream user would. --- build.zig | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/build.zig b/build.zig index 3ee2219..99e6957 100644 --- a/build.zig +++ b/build.zig @@ -2,14 +2,13 @@ const std = @import("std"); const vkgen = @import("src/index.zig"); pub const ShaderCompileStep = vkgen.ShaderCompileStep; -pub const VkGenerateStep = vkgen.VkGenerateStep; pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const vk_xml_path: ?[]const u8 = b.option([]const u8, "registry", "Override the path to the Vulkan registry"); - // using the package manager, this artifact can be obtained by the user + // Using the package manager, this artifact can be obtained by the user // through `b.dependency(, .{}).artifact("vulkan-zig-generator")`. // with that, the user need only `.addArg("path/to/vk.xml")`, and then obtain // a file source to the generated code with `.addOutputArg("vk.zig")` @@ -21,7 +20,7 @@ pub fn build(b: *std.Build) void { }); b.installArtifact(generator_exe); - // or they can skip all that, and just make sure to pass `.registry = "path/to/vk.xml"` to `b.dependency`, + // Or they can skip all that, and just make sure to pass `.registry = "path/to/vk.xml"` to `b.dependency`, // and then obtain the module directly via `.module("vulkan-zig")`. if (vk_xml_path) |path| { const generate_cmd = b.addRunArtifact(generator_exe); @@ -34,8 +33,26 @@ pub fn build(b: *std.Build) void { }); } - // remainder of the script is for local testing + // This section shows a crude example of how to build a program using vulkan-zig by + // calling the generator executable directly. + // First, obtain the path to vk.xml. In this example, we will just get it from the command line. + const example_registry = b.option([]const u8, "example-registry", "Override the path to the Vulkan registry used for the examples") orelse "examples/vk.xml"; + + // Obtain a reference to the generator. In a downstream build.zig, you would use + // `const generator_exe = b.dependency().artifact("vulkan-zig-generator");`. + // Here we are just going to use our own `generator_exe`. + + // Now create a run artifact, and pass the registry to the generator. The generator is normally + // invoked as `vulkan-zig-generator ` + const example_registry_generator_cmd = b.addRunArtifact(generator_exe); + example_registry_generator_cmd.addArg(example_registry); + // Obtain a reference to the generated file. + const example_vk_zig = example_registry_generator_cmd.addOutputFileArg("vk.zig"); + // And turn it into a module. + const example_vk_zig_module = b.addModule("example-vulkan-zig", .{ .root_source_file = example_vk_zig }); + + // Now build a Vulkan program. This is just a simple triangle from the vulkan tutorial. const triangle_exe = b.addExecutable(.{ .name = "triangle", .root_source_file = .{ .path = "examples/triangle.zig" }, @@ -46,12 +63,8 @@ pub fn build(b: *std.Build) void { b.installArtifact(triangle_exe); triangle_exe.linkSystemLibrary("glfw"); - const example_registry = b.option([]const u8, "example-registry", "Override the path to the Vulkan registry used for the examples") orelse "examples/vk.xml"; - const gen = VkGenerateStep.create(b, example_registry); - triangle_exe.root_module.addImport("vulkan", gen.getModule()); - - const vk_zig_install_step = b.addInstallFile(gen.getSource(), "src/vk.zig"); - b.getInstallStep().dependOn(&vk_zig_install_step.step); + // Add our module to the list of imports to make vulkan-zig available. + triangle_exe.root_module.addImport("vulkan", example_vk_zig_module); const shaders = ShaderCompileStep.create( b, @@ -68,6 +81,11 @@ pub fn build(b: *std.Build) void { const triangle_run_step = b.step("run-triangle", "Run the triangle example"); triangle_run_step.dependOn(&triangle_run_cmd.step); + // Remainder is for local testing. + + const example_vk_zig_install_step = b.addInstallFile(example_vk_zig, "src/vk.zig"); + b.getInstallStep().dependOn(&example_vk_zig_install_step.step); + const test_target = b.addTest(.{ .root_source_file = .{ .path = "src/index.zig" }, }); @@ -85,6 +103,6 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); - ref_all_decls_test.root_module.addImport("vulkan", gen.getModule()); + ref_all_decls_test.root_module.addImport("vulkan", example_vk_zig_module); test_step.dependOn(&ref_all_decls_test.step); } From 7ac69f90ef825e403638c7830b188030191e6566 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 22:22:01 +0200 Subject: [PATCH 5/7] use a separate build.zig for the example This gives a more concrete example of how to use vulkan-zig, including build commands as how a downstream user would use vulkan-zig. --- build.zig | 112 +++++++++++++---------------------------- examples/build.zig | 50 ++++++++++++++++++ examples/build.zig.zon | 14 ++++++ src/index.zig | 8 --- src/main.zig | 10 ++++ 5 files changed, 108 insertions(+), 86 deletions(-) create mode 100644 examples/build.zig create mode 100644 examples/build.zig.zon delete mode 100644 src/index.zig diff --git a/build.zig b/build.zig index 99e6957..9683228 100644 --- a/build.zig +++ b/build.zig @@ -1,12 +1,14 @@ const std = @import("std"); -const vkgen = @import("src/index.zig"); +const vkgen = @import("src/main.zig"); pub const ShaderCompileStep = vkgen.ShaderCompileStep; +pub const VkGenerateStep = vkgen.VkGenerateStep; pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const vk_xml_path: ?[]const u8 = b.option([]const u8, "registry", "Override the path to the Vulkan registry"); + const maybe_registry: ?[]const u8 = b.option([]const u8, "registry", "Set the path to the Vulkan registry (vk.xml)"); + const test_step = b.step("test", "Run all the tests"); // Using the package manager, this artifact can be obtained by the user // through `b.dependency(, .{}).artifact("vulkan-zig-generator")`. @@ -22,87 +24,41 @@ pub fn build(b: *std.Build) void { // Or they can skip all that, and just make sure to pass `.registry = "path/to/vk.xml"` to `b.dependency`, // and then obtain the module directly via `.module("vulkan-zig")`. - if (vk_xml_path) |path| { - const generate_cmd = b.addRunArtifact(generator_exe); + if (maybe_registry) |registry| { + const vk_generate_cmd = b.addRunArtifact(generator_exe); - if (!std.fs.path.isAbsolute(path)) @panic("Make sure to assign an absolute path to the `registry` option (see: std.Build.pathFromRoot).\n"); - generate_cmd.addArg(path); + if (!std.fs.path.isAbsolute(registry)) { + @panic("Make sure to assign an absolute path to the `registry` option (see: std.Build.pathFromRoot).\n"); + } - _ = b.addModule("vulkan-zig", .{ - .root_source_file = generate_cmd.addOutputFileArg("vk.zig"), + vk_generate_cmd.addArg(registry); + + const vk_zig = vk_generate_cmd.addOutputFileArg("vk.zig"); + const vk_zig_module = b.addModule("vulkan-zig", .{ + .root_source_file = vk_zig, }); + + // Also install vk.zig, if passed. + + const vk_zig_install_step = b.addInstallFile(vk_zig, "src/vk.zig"); + b.getInstallStep().dependOn(&vk_zig_install_step.step); + + // And run tests on this vk.zig too. + + // This test needs to be an object so that vulkan-zig can import types from the root. + // It does not need to run anyway. + const ref_all_decls_test = b.addObject(.{ + .name = "ref-all-decls-test", + .root_source_file = .{ .path = "test/ref_all_decls.zig" }, + .target = target, + .optimize = optimize, + }); + ref_all_decls_test.root_module.addImport("vulkan", vk_zig_module); + test_step.dependOn(&ref_all_decls_test.step); } - // This section shows a crude example of how to build a program using vulkan-zig by - // calling the generator executable directly. - - // First, obtain the path to vk.xml. In this example, we will just get it from the command line. - const example_registry = b.option([]const u8, "example-registry", "Override the path to the Vulkan registry used for the examples") orelse "examples/vk.xml"; - - // Obtain a reference to the generator. In a downstream build.zig, you would use - // `const generator_exe = b.dependency().artifact("vulkan-zig-generator");`. - // Here we are just going to use our own `generator_exe`. - - // Now create a run artifact, and pass the registry to the generator. The generator is normally - // invoked as `vulkan-zig-generator ` - const example_registry_generator_cmd = b.addRunArtifact(generator_exe); - example_registry_generator_cmd.addArg(example_registry); - // Obtain a reference to the generated file. - const example_vk_zig = example_registry_generator_cmd.addOutputFileArg("vk.zig"); - // And turn it into a module. - const example_vk_zig_module = b.addModule("example-vulkan-zig", .{ .root_source_file = example_vk_zig }); - - // Now build a Vulkan program. This is just a simple triangle from the vulkan tutorial. - const triangle_exe = b.addExecutable(.{ - .name = "triangle", - .root_source_file = .{ .path = "examples/triangle.zig" }, - .target = target, - .link_libc = true, - .optimize = optimize, - }); - b.installArtifact(triangle_exe); - triangle_exe.linkSystemLibrary("glfw"); - - // Add our module to the list of imports to make vulkan-zig available. - triangle_exe.root_module.addImport("vulkan", example_vk_zig_module); - - const shaders = ShaderCompileStep.create( - b, - &[_][]const u8{ "glslc", "--target-env=vulkan1.2" }, - "-o", - ); - shaders.add("triangle_vert", "examples/shaders/triangle.vert", .{}); - shaders.add("triangle_frag", "examples/shaders/triangle.frag", .{}); - triangle_exe.root_module.addImport("shaders", shaders.getModule()); - - const triangle_run_cmd = b.addRunArtifact(triangle_exe); - triangle_run_cmd.step.dependOn(b.getInstallStep()); - - const triangle_run_step = b.step("run-triangle", "Run the triangle example"); - triangle_run_step.dependOn(&triangle_run_cmd.step); - - // Remainder is for local testing. - - const example_vk_zig_install_step = b.addInstallFile(example_vk_zig, "src/vk.zig"); - b.getInstallStep().dependOn(&example_vk_zig_install_step.step); - const test_target = b.addTest(.{ - .root_source_file = .{ .path = "src/index.zig" }, + .root_source_file = .{ .path = "src/main.zig" }, }); - - const run_test = b.addRunArtifact(test_target); - - const test_step = b.step("test", "Run all the tests"); - test_step.dependOn(&run_test.step); - - // This test needs to be an object so that vulkan-zig can import types from the root. - // It does not need to run anyway. - const ref_all_decls_test = b.addObject(.{ - .name = "ref-all-decls-test", - .root_source_file = .{ .path = "test/ref_all_decls.zig" }, - .target = target, - .optimize = optimize, - }); - ref_all_decls_test.root_module.addImport("vulkan", example_vk_zig_module); - test_step.dependOn(&ref_all_decls_test.step); + test_step.dependOn(&b.addRunArtifact(test_target).step); } diff --git a/examples/build.zig b/examples/build.zig new file mode 100644 index 0000000..1420180 --- /dev/null +++ b/examples/build.zig @@ -0,0 +1,50 @@ +const std = @import("std"); + +const vkgen = @import("vulkan_zig"); +const ShaderCompileStep = vkgen.ShaderCompileStep; + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const maybe_override_registry = b.option([]const u8, "override-registry", "Override the path to the Vulkan registry used for the examples"); + + const registry = b.dependency("vulkan_headers", .{}).path("registry/vk.xml"); + + const triangle_exe = b.addExecutable(.{ + .name = "triangle", + .root_source_file = .{ .path = "triangle.zig" }, + .target = target, + .link_libc = true, + .optimize = optimize, + }); + b.installArtifact(triangle_exe); + triangle_exe.linkSystemLibrary("glfw"); + + const vk_gen = b.dependency("vulkan_zig", .{}).artifact("vulkan-zig-generator"); + const vk_generate_cmd = b.addRunArtifact(vk_gen); + + if (maybe_override_registry) |override_registry| { + vk_generate_cmd.addFileArg(.{ .path = override_registry }); + } else { + vk_generate_cmd.addFileArg(registry); + } + + triangle_exe.root_module.addAnonymousImport("vulkan", .{ + .root_source_file = vk_generate_cmd.addOutputFileArg("vk.zig"), + }); + + const shaders = ShaderCompileStep.create( + b, + &[_][]const u8{ "glslc", "--target-env=vulkan1.2" }, + "-o", + ); + shaders.add("triangle_vert", "shaders/triangle.vert", .{}); + shaders.add("triangle_frag", "shaders/triangle.frag", .{}); + triangle_exe.root_module.addImport("shaders", shaders.getModule()); + + const triangle_run_cmd = b.addRunArtifact(triangle_exe); + triangle_run_cmd.step.dependOn(b.getInstallStep()); + + const triangle_run_step = b.step("run-triangle", "Run the triangle example"); + triangle_run_step.dependOn(&triangle_run_cmd.step); +} diff --git a/examples/build.zig.zon b/examples/build.zig.zon new file mode 100644 index 0000000..d461ba2 --- /dev/null +++ b/examples/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "vulkan-zig-examples", + .version = "0.1.0", + .dependencies = .{ + .vulkan_zig = .{ + .path = "..", + }, + .vulkan_headers = .{ + .url = "https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.3.283.tar.gz", + .hash = "1220a7e73d72a0d56bc2a65f9d8999a7c019e42260a0744c408d1cded111bc205e10", + }, + }, + .paths = .{""}, +} diff --git a/src/index.zig b/src/index.zig deleted file mode 100644 index 05ca2fe..0000000 --- a/src/index.zig +++ /dev/null @@ -1,8 +0,0 @@ -pub const generateVk = @import("vulkan/generator.zig").generate; -pub const VkGenerateStep = @import("vulkan/build_integration.zig").GenerateStep; -pub const ShaderCompileStep = @import("build_integration.zig").ShaderCompileStep; - -test "main" { - _ = @import("xml.zig"); - _ = @import("vulkan/c_parse.zig"); -} diff --git a/src/main.zig b/src/main.zig index fc6c012..050d809 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,10 @@ const std = @import("std"); const generator = @import("vulkan/generator.zig"); +pub const generateVk = generator.generate; +pub const VkGenerateStep = @import("vulkan/build_integration.zig").GenerateStep; +pub const ShaderCompileStep = @import("build_integration.zig").ShaderCompileStep; + fn invalidUsage(prog_name: []const u8, comptime fmt: []const u8, args: anytype) noreturn { std.log.err(fmt, args); std.log.err("see {s} --help for usage", .{prog_name}); @@ -127,3 +131,9 @@ pub fn main() void { std.process.exit(1); }; } + +test "main" { + _ = @import("xml.zig"); + _ = @import("vulkan/c_parse.zig"); +} + From 883ab2c2c482ed279e99cbe0e67a2e1e853fb8d8 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 22:22:47 +0200 Subject: [PATCH 6/7] update and fix README Updates and fixes the explanations for how to use vulkan-zig so that they are up-to-date in general, and up-to-date with the recent changes to building the example. --- README.md | 107 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 33065b2..438e8ab 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ vulkan-zig attempts to provide a better experience to programming Vulkan applica vulkan-zig is automatically tested daily against the latest vk.xml and zig, and supports vk.xml from version 1.x.163. +## Example + +A partial implementation of https://vulkan-tutorial.com is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build --build-file $(pwd)/examples/build.zig run-triangle` in vulkan-zig's root. See in particular the [build file](examples/build.zig), which contains a concrete example of how to use vulkan-zig as a dependency. + ### Zig versions vulkan-zig aims to be always compatible with the ever-changing Zig master branch (however, development may lag a few days behind). Sometimes, the Zig master branch breaks a bunch of functionality however, which may make the latest version vulkan-zig incompatible with older releases of Zig. This repository aims to have a version compatible for both the latest Zig master, and the latest Zig release. The `master` branch is compatible with the `master` branch of Zig, and versions for older versions of Zig are maintained in the `zig--compat` branch. @@ -18,38 +22,19 @@ vulkan-zig aims to be always compatible with the ever-changing Zig master branch ## Features ### CLI-interface + A CLI-interface is provided to generate vk.zig from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/main/xml), which is built by default when invoking `zig build` in the project root. To generate vk.zig, simply invoke the program as follows: ``` $ zig-out/bin/vulkan-zig-generator path/to/vk.xml output/path/to/vk.zig ``` This reads the xml file, parses its contents, renders the Vulkan bindings, and formats file, before writing the result to the output path. While the intended usage of vulkan-zig is through direct generation from build.zig (see below), the CLI-interface can be used for one-off generation and vendoring the result. -NOTE: you need to replace `path/to/vk.xml` with the spec path from whatever source you prefer, here are some examples orderered from the most recommended: -- Vulkan SDK, you need the package installed on your system with environment path setup but its the most stable option: - /share/vulkan/registry/vk.xml -- Vulkan-Headers repo, doesn't require the Vulkan SDK in the build environment: - https://github.com/KhronosGroup/Vulkan-Headers/blob/main/registry/vk.xml -- local vk.xml inside examples: - vulkan-zig\examples\vk.xml -### Generation from build.zig -Vulkan bindings can be generated from the Vulkan XML registry at compile time with build.zig, by using the provided Vulkan generation step: -```zig -const vkgen = @import("vulkan-zig/src/index.zig"); - -pub fn build(b: *Builder) void { - ... - const exe = b.addExecutable("my-executable", "src/main.zig"); - - // Create a step that generates vk.zig (stored in zig-cache) from the provided vulkan registry. - const gen = vkgen.VkGenerateStep.create(b, "path/to/vk.xml"); - - // Add the generated file as package to the final executable - exe.addModule("vulkan", gen.getModule()); -} -``` -This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addModule`, after which the bindings will be made available to the executable under the name passed to `getModule`. +`path/to/vk.xml` can be obtained from several sources: +- From the LunarG Vulkan SDK. This can either be obtained from [LunarG](https://www.lunarg.com/vulkan-sdk) or usually using the package manager. The registry can then be found at `$VULKAN_SDK/share/vulkan/registry/vk.xml`. +- Directly from the [Vulkan-Headers GitHub repository](https://github.com/KhronosGroup/Vulkan-Headers/blob/main/registry/vk.xml). ### Generation with the package manager from build.zig + There is also support for adding this project as a dependency through zig package manager in its current form. In order to do this, add this repo as a dependency in your build.zig.zon: ```zig .{ @@ -69,26 +54,69 @@ const vkzig_dep = b.dependency("vulkan_zig", .{ .registry = @as([]const u8, b.pathFromRoot("path/to/vk.xml")), }); const vkzig_bindings = vkzig_dep.module("vulkan-zig"); -exe.addModule("vulkan-zig", vkzig_bindings); +exe.addModule("vulkan", vkzig_bindings); ``` -That will allow you to `@import("vulkan-zig")` in your executable's source. +That will allow you to `@import("vulkan")` in your executable's source. ### Manual generation with the package manager from build.zig -In the event you have a specific need for it, the generator executable is made available through the dependency, allowing you to run the executable as a build step in your own build.zig file. -Doing so should look a bit like this: + +Bindings can also be generated by invoking the generator directly. This may be useful is some special cases, for example, it integrates particularly well with fetching the registry via the package manager. This can be done by adding the Vulkan-Headers repository to your dependencies, and then passing the `vk.xml` inside it to vulkan-zig-generator: ```zig -const vk_gen = b.dependency("vulkan_zig", .{}).artifact("vulkan-zig-generator"); // get generator executable reference - -const generate_cmd = b.addRunArtifact(vk_gen); -generate_cmd.addArg(b.pathFromRoot("vk.xml")); // path to xml file to use when generating the bindings +.{ + // -- snip -- + .depdendencies = .{ + // -- snip -- + .vulkan_headers = .{ + .url = "https://github.com/KhronosGroup/Vulkan-Headers/archive/.tar.gz", + .hash = "", + }, + }, +} +``` +And then pass `vk.xml` to vulkan-zig-generator as follows: +```zig +// Get the (lazy) path to vk.xml: +const registry = b.dependency("vulkan_headers", .{}).path("registry/vk.xml"); +// Get generator executable reference +const vk_gen = b.dependency("vulkan_zig", .{}).artifact("vulkan-zig-generator"); +// Set up a run step to generate the bindings +const vk_generate_cmd = b.addRunArtifact(vk_gen); +// Pass the registry to the generator +generate_cmd.addArg(registry); +// Create a module from the generator's output... const vulkan_zig = b.addModule("vulkan-zig", .{ - .source_file = generate_cmd.addOutputFileArg("vk.zig"), // this is the FileSource representing the generated bindings + .root_source_file = vk_generate_cmd.addOutputFileArg("vk.zig"), }); -exe.addModule("vulkan-zig", vulkan_zig); +// ... and pass it as a module to your executable's build command +exe.root_module.addImport("vulkan", vulkan_zig); ``` +See [examples/build.zig](examples/build.zig) and [examples/build.zig.zon](examples/build.zig.zon) for a concrete example. + +### (Deprecated) Generation from build.zig + +Vulkan bindings can be generated from the Vulkan XML registry at compile time with build.zig, by using the provided Vulkan generation step. This requires adding vulkan-zig to your dependencies as shown above. After than, vulkan-zig can be imported at build time as follows: +```zig +const vkgen = @import("vulkan_zig"); + +pub fn build(b: *Builder) void { + ... + const exe = b.addExecutable("my-executable", "src/main.zig"); + + // Create a step that generates vk.zig (stored in zig-cache) from the provided vulkan registry. + const gen = vkgen.VkGenerateStep.create(b, "path/to/vk.xml"); + + // Add the generated file as package to the final executable + exe.addModule("vulkan", gen.getModule()); +} +``` +This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addModule`, after which the bindings will be made available to the executable under the name passed to `getModule`. + +This feature is only provided for legacy reasons. If you are still using this, please migrate to one of the methods that involve the package manager, as this method will be removed in the near future. + ### Function & field renaming + Functions and fields are renamed to be more or less in line with [Zig's standard library style](https://ziglang.org/documentation/master/#Style-Guide): * The vk prefix is removed everywhere * Structs like `VkInstanceCreateInfo` are renamed to `InstanceCreateInfo`. @@ -100,6 +128,7 @@ Functions and fields are renamed to be more or less in line with [Zig's standard * Any name which is either an illegal Zig name or a reserved identifier is rendered using `@"name"` syntax. For example, `VK_IMAGE_TYPE_2D` is translated to `@"2d"`. ### Function pointers & Wrappers + vulkan-zig provides no integration for statically linking libvulkan, and these symbols are not generated at all. Instead, vulkan functions are to be loaded dynamically. For each Vulkan function, a function pointer type is generated using the exact parameters and return types as defined by the Vulkan specification: ```zig pub const PfnCreateInstance = fn ( @@ -204,6 +233,7 @@ By default, wrapper `load` functions return `error.CommandLoadFailure` if a call One can access the underlying unwrapped C functions by doing `wrapper.dispatch.vkFuncYouWant(..)`. ### Bitflags + Packed structs of bools are used for bit flags in vulkan-zig, instead of both a `FlagBits` and `Flags` variant. Places where either of these variants are used are both replaced by this packed struct instead. This means that even in places where just one flag would normally be accepted, the packed struct is accepted. The programmer is responsible for only enabling a single bit. Each bit is defaulted to `false`, and the first `bool` is aligned to guarantee the overal alignment @@ -252,6 +282,7 @@ pub fn FlagsMixin(comptime FlagsType: type) type { ``` ### Handles + Handles are generated to a non-exhaustive enum, backed by a `u64` for non-dispatchable handles and `usize` for dispatchable ones: ```zig const Instance = extern enum(usize) { null_handle = 0, _ }; @@ -259,6 +290,7 @@ const Instance = extern enum(usize) { null_handle = 0, _ }; This means that handles are type-safe even when compiling for a 32-bit target. ### Struct defaults + Defaults are generated for certain fields of structs: * sType is defaulted to the appropriate value. * pNext is defaulted to `null`. @@ -273,6 +305,7 @@ pub const InstanceCreateInfo = extern struct { ``` ### Pointer types + Pointer types in both commands (wrapped and function pointers) and struct fields are augmented with the following information, where available in the registry: * Pointer optional-ness. * Pointer const-ness. @@ -281,6 +314,7 @@ Pointer types in both commands (wrapped and function pointers) and struct fields Note that this information is not everywhere as useful in the registry, leading to places where optional-ness is not correct. Most notably, CreateInfo type structures which take a slice often have the item count marked as optional, but the pointer itself not. As of yet, this is not fixed in vulkan-zig. If drivers properly follow the Vulkan specification, these can be initialized to `undefined`, however, [that is not always the case](https://zeux.io/2019/07/17/serializing-pipeline-cache/). ### Platform types + Defaults with the same ABI layout are generated for most platform-defined types. These can either by bitcasted to, or overridden by defining them in the project root: ```zig pub const xcb_connection_t = if (@hasDecl(root, "xcb_connection_t")) root.xcb_connection_t else @Type(.Opaque); @@ -316,12 +350,11 @@ pub const ${name} align(@alignOf(u32)) = @embedFile("${path}").*; See [build.zig](build.zig) for a working example. ## Limitations + * vulkan-zig has as of yet no functionality for selecting feature levels and extensions when generating bindings. This is because when an extension is promoted to Vulkan core, its fields and commands are renamed to lose the extensions author tag (for example, VkSemaphoreWaitFlagsKHR was renamed to VkSemaphoreWaitFlags when it was promoted from an extension to Vulkan 1.2 core). This leads to inconsistencies when only items from up to a certain feature level is included, as these promoted items then need to re-gain a tag. -## Example -A partial implementation of https://vulkan-tutorial.com is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root. - ## See also + * Implementation of https://vulkan-tutorial.com using `@cImport`'ed bindings: https://github.com/andrewrk/zig-vulkan-triangle. * Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers * Zig bindings for GLFW: https://github.com/hexops/mach-glfw From 65f1b0252b570641b38646b79c6ee6e70f860085 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 28 Apr 2024 22:39:02 +0200 Subject: [PATCH 7/7] ci: build example separate and fix tests Apparently the tests werent executing for some reason?? --- .github/workflows/build.yml | 13 ++++++++----- build.zig | 4 ---- src/main.zig | 1 - test/ref_all_decls.zig | 17 ++++++++++++++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 305c961..356d7be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,9 +23,6 @@ jobs: - name: Check formatting run: zig fmt --check . - - name: Test - run: zig build test - - name: Fetch latest Vulkan SDK run: | wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add - @@ -36,8 +33,14 @@ jobs: - name: Fetch latest vk.xml run: wget https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/main/xml/vk.xml - - name: Build with latest zig & vk.xml - run: zig build -Dexample-registry=./vk.xml + - name: Test and install with latest zig & latest vk.xml + run: zig build test install -Dregistry=./vk.xml + + - name: Build example with latest zig & vk.xml from dependency + run: zig build --build-file $(pwd)/examples/build.zig + + - name: Build example with latest zig & latest vk.xml + run: zig build --build-file $(pwd)/examples/build.zig -Doverride-registry=./vk.xml - name: Archive vk.zig uses: actions/upload-artifact@v4 diff --git a/build.zig b/build.zig index 9683228..9ce0f26 100644 --- a/build.zig +++ b/build.zig @@ -27,10 +27,6 @@ pub fn build(b: *std.Build) void { if (maybe_registry) |registry| { const vk_generate_cmd = b.addRunArtifact(generator_exe); - if (!std.fs.path.isAbsolute(registry)) { - @panic("Make sure to assign an absolute path to the `registry` option (see: std.Build.pathFromRoot).\n"); - } - vk_generate_cmd.addArg(registry); const vk_zig = vk_generate_cmd.addOutputFileArg("vk.zig"); diff --git a/src/main.zig b/src/main.zig index 050d809..742779b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -136,4 +136,3 @@ test "main" { _ = @import("xml.zig"); _ = @import("vulkan/c_parse.zig"); } - diff --git a/test/ref_all_decls.zig b/test/ref_all_decls.zig index 4cf6279..ed710fe 100644 --- a/test/ref_all_decls.zig +++ b/test/ref_all_decls.zig @@ -3,8 +3,14 @@ const vk = @import("vulkan"); // Provide bogus defaults for unknown platform types // The actual type does not really matter here... -pub const GgpFrameToken = u32; pub const GgpStreamDescriptor = u32; +pub const GgpFrameToken = u32; +pub const _screen_buffer = u32; +pub const NvSciSyncAttrList = u32; +pub const NvSciSyncObj = u32; +pub const NvSciSyncFence = u32; +pub const NvSciBufAttrList = u32; +pub const NvSciBufObj = u32; pub const ANativeWindow = u32; pub const AHardwareBuffer = u32; pub const CAMetalLayer = u32; @@ -62,11 +68,16 @@ pub const StdVideoDecodeH265PictureInfo = u32; pub const StdVideoDecodeH265ReferenceInfo = u32; pub const StdVideoDecodeH265PictureInfoFlags = u32; pub const StdVideoDecodeH265ReferenceInfoFlags = u32; +pub const StdVideoAV1Profile = u32; +pub const StdVideoAV1Level = u32; +pub const StdVideoAV1SequenceHeader = u32; +pub const StdVideoDecodeAV1PictureInfo = u32; +pub const StdVideoDecodeAV1ReferenceInfo = u32; pub const StdVideoEncodeH264SliceHeader = u32; pub const StdVideoEncodeH264PictureInfo = u32; pub const StdVideoEncodeH264ReferenceInfo = u32; pub const StdVideoEncodeH264SliceHeaderFlags = u32; -pub const StdVideoEncodeH264RefMemMgmtCtrlOperations = u32; +pub const StdVideoEncodeH264ReferenceListsInfo = u32; pub const StdVideoEncodeH264PictureInfoFlags = u32; pub const StdVideoEncodeH264ReferenceInfoFlags = u32; pub const StdVideoEncodeH264RefMgmtFlags = u32; @@ -76,7 +87,7 @@ pub const StdVideoEncodeH265PictureInfoFlags = u32; pub const StdVideoEncodeH265PictureInfo = u32; pub const StdVideoEncodeH265SliceSegmentHeader = u32; pub const StdVideoEncodeH265ReferenceInfo = u32; -pub const StdVideoEncodeH265ReferenceModifications = u32; +pub const StdVideoEncodeH265ReferenceListsInfo = u32; pub const StdVideoEncodeH265SliceSegmentHeaderFlags = u32; pub const StdVideoEncodeH265ReferenceInfoFlags = u32; pub const StdVideoEncodeH265ReferenceModificationFlags = u32;