Merge pull request #193 from alichraghi/master

update to latest zig
This commit is contained in:
Robin Voetter
2025-07-19 13:30:49 +02:00
committed by GitHub
9 changed files with 1788 additions and 1778 deletions

View File

@@ -7,15 +7,19 @@ pub fn build(b: *std.Build) void {
const maybe_video = b.option(std.Build.LazyPath, "video", "Set the path to the Vulkan Video registry (video.xml)"); const maybe_video = b.option(std.Build.LazyPath, "video", "Set the path to the Vulkan Video registry (video.xml)");
const test_step = b.step("test", "Run all the tests"); const test_step = b.step("test", "Run all the tests");
const root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// 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(<name in build.zig.zon>, .{}).artifact("vulkan-zig-generator")`. // through `b.dependency(<name in build.zig.zon>, .{}).artifact("vulkan-zig-generator")`.
// with that, the user need only `.addArg("path/to/vk.xml")`, and then obtain // 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")` // a file source to the generated code with `.addOutputArg("vk.zig")`
const generator_exe = b.addExecutable(.{ const generator_exe = b.addExecutable(.{
.name = "vulkan-zig-generator", .name = "vulkan-zig-generator",
.root_source_file = b.path("src/main.zig"), .root_module = root_module,
.target = target,
.optimize = optimize,
}); });
b.installArtifact(generator_exe); b.installArtifact(generator_exe);
@@ -47,16 +51,16 @@ pub fn build(b: *std.Build) void {
// It does not need to run anyway. // It does not need to run anyway.
const ref_all_decls_test = b.addObject(.{ const ref_all_decls_test = b.addObject(.{
.name = "ref-all-decls-test", .name = "ref-all-decls-test",
.root_module = b.createModule(.{
.root_source_file = b.path("test/ref_all_decls.zig"), .root_source_file = b.path("test/ref_all_decls.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}),
}); });
ref_all_decls_test.root_module.addImport("vulkan", vk_zig_module); ref_all_decls_test.root_module.addImport("vulkan", vk_zig_module);
test_step.dependOn(&ref_all_decls_test.step); test_step.dependOn(&ref_all_decls_test.step);
} }
const test_target = b.addTest(.{ const test_target = b.addTest(.{ .root_module = root_module });
.root_source_file = b.path("src/main.zig"),
});
test_step.dependOn(&b.addRunArtifact(test_target).step); test_step.dependOn(&b.addRunArtifact(test_target).step);
} }

View File

@@ -12,10 +12,14 @@ pub fn build(b: *std.Build) void {
const triangle_exe = b.addExecutable(.{ const triangle_exe = b.addExecutable(.{
.name = "triangle", .name = "triangle",
.root_module = b.createModule(.{
.root_source_file = b.path("triangle.zig"), .root_source_file = b.path("triangle.zig"),
.target = target, .target = target,
.link_libc = true, .link_libc = true,
.optimize = optimize, .optimize = optimize,
}),
// TODO: Remove this once x86_64 is stable
.use_llvm = true,
}); });
b.installArtifact(triangle_exe); b.installArtifact(triangle_exe);
triangle_exe.linkSystemLibrary("glfw"); triangle_exe.linkSystemLibrary("glfw");
@@ -33,17 +37,18 @@ pub fn build(b: *std.Build) void {
if (use_zig_shaders) { if (use_zig_shaders) {
const spirv_target = b.resolveTargetQuery(.{ const spirv_target = b.resolveTargetQuery(.{
.cpu_arch = .spirv64, .cpu_arch = .spirv32,
.os_tag = .vulkan, .os_tag = .vulkan,
.cpu_model = .{ .explicit = &std.Target.spirv.cpu.vulkan_v1_2 }, .cpu_model = .{ .explicit = &std.Target.spirv.cpu.vulkan_v1_2 },
.cpu_features_add = std.Target.spirv.featureSet(&.{.int64}),
.ofmt = .spirv, .ofmt = .spirv,
}); });
const vert_spv = b.addObject(.{ const vert_spv = b.addObject(.{
.name = "vertex_shader", .name = "vertex_shader",
.root_module = b.createModule(.{
.root_source_file = b.path("shaders/vertex.zig"), .root_source_file = b.path("shaders/vertex.zig"),
.target = spirv_target, .target = spirv_target,
}),
.use_llvm = false, .use_llvm = false,
}); });
triangle_exe.root_module.addAnonymousImport( triangle_exe.root_module.addAnonymousImport(
@@ -53,8 +58,10 @@ pub fn build(b: *std.Build) void {
const frag_spv = b.addObject(.{ const frag_spv = b.addObject(.{
.name = "fragment_shader", .name = "fragment_shader",
.root_module = b.createModule(.{
.root_source_file = b.path("shaders/fragment.zig"), .root_source_file = b.path("shaders/fragment.zig"),
.target = spirv_target, .target = spirv_target,
}),
.use_llvm = false, .use_llvm = false,
}); });
triangle_exe.root_module.addAnonymousImport( triangle_exe.root_module.addAnonymousImport(

View File

@@ -8,6 +8,5 @@ export fn main() callconv(.spirv_fragment) void {
gpu.location(&v_color, 0); gpu.location(&v_color, 0);
gpu.location(&f_color, 0); gpu.location(&f_color, 0);
const temp: @Vector(4, f32) = .{ v_color[0], v_color[1], v_color[2], 1.0 }; f_color = .{ v_color[0], v_color[1], v_color[2], 1.0 };
f_color = temp;
} }

View File

@@ -52,13 +52,8 @@ pub fn isZigPrimitiveType(name: []const u8) bool {
return false; return false;
} }
pub fn writeIdentifier(writer: anytype, id: []const u8) !void { pub fn writeIdentifier(w: *std.io.Writer, id: []const u8) !void {
// https://github.com/ziglang/zig/issues/2897 try w.print("{f}", .{std.zig.fmtId(id)});
if (isZigPrimitiveType(id)) {
try writer.print("@\"{}\"", .{std.zig.fmtEscapes(id)});
} else {
try writer.print("{}", .{std.zig.fmtId(id)});
}
} }
pub const CaseStyle = enum { pub const CaseStyle = enum {
@@ -196,13 +191,13 @@ pub const IdRenderer = struct {
} }
} }
pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void { pub fn renderFmt(self: *IdRenderer, out: *std.Io.Writer, comptime fmt: []const u8, args: anytype) !void {
self.text_cache.items.len = 0; self.text_cache.items.len = 0;
try std.fmt.format(self.text_cache.writer(), fmt, args); try std.fmt.format(self.text_cache.writer(), fmt, args);
try writeIdentifier(out, self.text_cache.items); try writeIdentifier(out, self.text_cache.items);
} }
pub fn renderWithCase(self: *IdRenderer, out: anytype, case_style: CaseStyle, id: []const u8) !void { pub fn renderWithCase(self: *IdRenderer, out: *std.Io.Writer, case_style: CaseStyle, id: []const u8) !void {
const tag = self.getAuthorTag(id); const tag = self.getAuthorTag(id);
// The trailing underscore doesn't need to be removed here as its removed by the SegmentIterator. // The trailing underscore doesn't need to be removed here as its removed by the SegmentIterator.
const adjusted_id = if (tag) |name| id[0 .. id.len - name.len] else id; const adjusted_id = if (tag) |name| id[0 .. id.len - name.len] else id;

View File

@@ -8,17 +8,18 @@ fn invalidUsage(prog_name: []const u8, comptime fmt: []const u8, args: anytype)
} }
fn reportParseErrors(tree: std.zig.Ast) !void { fn reportParseErrors(tree: std.zig.Ast) !void {
const stderr = std.io.getStdErr().writer(); var buf: [1024]u8 = undefined;
var stderr = std.fs.File.stderr().writer(&buf);
const w = &stderr.interface;
for (tree.errors) |err| { for (tree.errors) |err| {
const loc = tree.tokenLocation(0, err.token); const loc = tree.tokenLocation(0, err.token);
try stderr.print("(vulkan-zig error):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 }); try w.print("(vulkan-zig error):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
try tree.renderError(err, stderr); try tree.renderError(err, w);
try stderr.print("\n{s}\n", .{tree.source[loc.line_start..loc.line_end]}); try w.print("\n{s}\n", .{tree.source[loc.line_start..loc.line_end]});
for (0..loc.column) |_| { for (0..loc.column) |_| {
try stderr.writeAll(" "); try w.writeAll(" ");
} }
try stderr.writeAll("^\n"); try w.writeAll("^\n");
} }
} }
@@ -41,7 +42,9 @@ pub fn main() !void {
while (args.next()) |arg| { while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) { if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
@setEvalBranchQuota(2000); @setEvalBranchQuota(2000);
std.io.getStdOut().writer().print( var buf: [1024]u8 = undefined;
var w = std.fs.File.stdout().writer(&buf);
w.interface.print(
\\Utility to generate a Zig binding from the Vulkan XML API registry. \\Utility to generate a Zig binding from the Vulkan XML API registry.
\\ \\
\\The most recent Vulkan XML API registry can be obtained from \\The most recent Vulkan XML API registry can be obtained from
@@ -60,8 +63,7 @@ pub fn main() !void {
, ,
.{prog_name}, .{prog_name},
) catch |err| { ) catch |err| {
std.log.err("failed to write to stdout: {s}", .{@errorName(err)}); std.process.fatal("failed to write to stdout: {s}", .{@errorName(err)});
std.process.exit(1);
}; };
return; return;
} else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--api")) { } else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--api")) {
@@ -96,20 +98,24 @@ pub fn main() !void {
const cwd = std.fs.cwd(); const cwd = std.fs.cwd();
const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| { const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| {
std.log.err("failed to open input file '{s}' ({s})", .{ xml_path, @errorName(err) }); std.process.fatal("failed to open input file '{s}' ({s})", .{ xml_path, @errorName(err) });
std.process.exit(1);
}; };
const maybe_video_xml_src = if (maybe_video_xml_path) |video_xml_path| const maybe_video_xml_src = if (maybe_video_xml_path) |video_xml_path|
cwd.readFileAlloc(allocator, video_xml_path, std.math.maxInt(usize)) catch |err| { cwd.readFileAlloc(allocator, video_xml_path, std.math.maxInt(usize)) catch |err| {
std.log.err("failed to open input file '{s}' ({s})", .{ video_xml_path, @errorName(err) }); std.process.fatal("failed to open input file '{s}' ({s})", .{ video_xml_path, @errorName(err) });
std.process.exit(1);
} }
else else
null; null;
var out_buffer = std.ArrayList(u8).init(allocator); var out_buffer = std.ArrayList(u8).init(allocator);
generator.generate(allocator, api, xml_src, maybe_video_xml_src, out_buffer.writer()) catch |err| switch (err) { var w = out_buffer.writer().adaptToNewApi();
generator.generate(allocator, api, xml_src, maybe_video_xml_src, &w.new_interface) catch |err| {
if (debug) {
return err;
}
switch (err) {
error.InvalidXml => { error.InvalidXml => {
std.log.err("invalid vulkan registry - invalid xml", .{}); std.log.err("invalid vulkan registry - invalid xml", .{});
std.log.err("please check that the correct vk.xml file is passed", .{}); std.log.err("please check that the correct vk.xml file is passed", .{});
@@ -126,7 +132,8 @@ pub fn main() !void {
std.log.err("please make a bug report at https://github.com/Snektron/vulkan-zig/issues/", .{}); std.log.err("please make a bug report at https://github.com/Snektron/vulkan-zig/issues/", .{});
std.process.exit(1); std.process.exit(1);
}, },
error.OutOfMemory => @panic("oom"), error.OutOfMemory, error.WriteFailed => @panic("oom"),
}
}; };
out_buffer.append(0) catch @panic("oom"); out_buffer.append(0) catch @panic("oom");
@@ -143,22 +150,20 @@ pub fn main() !void {
std.log.err("or run with --debug to write out unformatted source", .{}); std.log.err("or run with --debug to write out unformatted source", .{});
reportParseErrors(tree) catch |err| { reportParseErrors(tree) catch |err| {
std.log.err("failed to dump ast errors: {s}", .{@errorName(err)}); std.process.fatal("failed to dump ast errors: {s}", .{@errorName(err)});
std.process.exit(1);
}; };
if (debug) { if (debug) {
break :blk src; break :blk src;
} }
std.process.exit(1); std.process.exit(1);
} else tree.render(allocator) catch |err| switch (err) { } else tree.renderAlloc(allocator) catch |err| switch (err) {
error.OutOfMemory => @panic("oom"), error.OutOfMemory => @panic("oom"),
}; };
if (std.fs.path.dirname(out_path)) |dir| { if (std.fs.path.dirname(out_path)) |dir| {
cwd.makePath(dir) catch |err| { cwd.makePath(dir) catch |err| {
std.log.err("failed to create output directory '{s}' ({s})", .{ dir, @errorName(err) }); std.process.fatal("failed to create output directory '{s}' ({s})", .{ dir, @errorName(err) });
std.process.exit(1);
}; };
} }
@@ -166,8 +171,7 @@ pub fn main() !void {
.sub_path = out_path, .sub_path = out_path,
.data = formatted, .data = formatted,
}) catch |err| { }) catch |err| {
std.log.err("failed to write to output file '{s}' ({s})", .{ out_path, @errorName(err) }); std.process.fatal("failed to write to output file '{s}' ({s})", .{ out_path, @errorName(err) });
std.process.exit(1);
}; };
} }

View File

@@ -186,7 +186,7 @@ pub const Generator = struct {
self.registry.decls.len = i; self.registry.decls.len = i;
} }
fn render(self: *Generator, writer: anytype) !void { fn render(self: *Generator, writer: *std.Io.Writer) !void {
try renderRegistry(writer, self.arena.allocator(), &self.registry, &self.id_renderer, self.have_video); try renderRegistry(writer, self.arena.allocator(), &self.registry, &self.id_renderer, self.have_video);
} }
}; };
@@ -204,7 +204,7 @@ pub fn generate(
api: Api, api: Api,
spec_xml: []const u8, spec_xml: []const u8,
maybe_video_spec_xml: ?[]const u8, maybe_video_spec_xml: ?[]const u8,
writer: anytype, writer: *std.Io.Writer,
) !void { ) !void {
const spec = xml.parse(allocator, spec_xml) catch |err| switch (err) { const spec = xml.parse(allocator, spec_xml) catch |err| switch (err) {
error.InvalidDocument, error.InvalidDocument,

View File

@@ -365,10 +365,18 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
else => break, else => break,
}; };
if (it.next()) |_| { if (it.next()) |_| ignore: {
// There are more elements in the `len` attribute than there are pointers // There are more elements in the `len` attribute than there are pointers
// Something probably went wrong // Something probably went wrong
std.log.err("len: {s}", .{lens}); switch (current_type_info.*) {
.name => |name| if (std.mem.eql(u8, name, "StdVideoH265SubLayerHrdParameters")) {
// Known issue: https://github.com/KhronosGroup/Vulkan-Docs/issues/2557
break :ignore;
},
else => {},
}
std.log.err("excessive pointer lengths: {s}", .{lens});
return error.InvalidRegistry; return error.InvalidRegistry;
} }
} }

View File

@@ -17,15 +17,15 @@ const preamble =
\\const Allocator = std.mem.Allocator; \\const Allocator = std.mem.Allocator;
\\ \\
\\pub const vulkan_call_conv: std.builtin.CallingConvention = if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) \\pub const vulkan_call_conv: std.builtin.CallingConvention = if (builtin.os.tag == .windows and builtin.cpu.arch == .x86)
\\ .Stdcall \\ .winapi
\\ else if (builtin.abi == .android and (builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb()) and std.Target.arm.featureSetHas(builtin.cpu.features, .has_v7) and builtin.cpu.arch.ptrBitWidth() == 32) \\ else if (builtin.abi == .android and (builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb()) and std.Target.arm.featureSetHas(builtin.cpu.features, .has_v7) and builtin.cpu.arch.ptrBitWidth() == 32)
\\ // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" \\ // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
\\ // calling convention, i.e. float parameters are passed in registers. This \\ // calling convention, i.e. float parameters are passed in registers. This
\\ // is true even if the rest of the application passes floats on the stack, \\ // is true even if the rest of the application passes floats on the stack,
\\ // as it does by default when compiling for the armeabi-v7a NDK ABI. \\ // as it does by default when compiling for the armeabi-v7a NDK ABI.
\\ .AAPCSVFP \\ .arm_aapcs_vfp
\\ else \\ else
\\ .C; \\ .c;
// Note: Keep in sync with flag_functions // Note: Keep in sync with flag_functions
\\pub fn FlagsMixin(comptime FlagsType: type) type { \\pub fn FlagsMixin(comptime FlagsType: type) type {
\\ return struct { \\ return struct {
@@ -336,11 +336,9 @@ pub fn trimVkNamespace(id: []const u8) []const u8 {
return id; return id;
} }
fn Renderer(comptime WriterType: type) type { const Renderer = struct {
return struct {
const Self = @This(); const Self = @This();
const WriteError = WriterType.Error; const RenderTypeInfoError = std.Io.Writer.Error || std.fmt.ParseIntError || error{ OutOfMemory, InvalidRegistry };
const RenderTypeInfoError = WriteError || std.fmt.ParseIntError || error{ OutOfMemory, InvalidRegistry };
const BitflagName = struct { const BitflagName = struct {
/// Name without FlagBits, so VkSurfaceTransformFlagBitsKHR /// Name without FlagBits, so VkSurfaceTransformFlagBitsKHR
@@ -374,7 +372,7 @@ fn Renderer(comptime WriterType: type) type {
}, },
}; };
writer: WriterType, writer: *std.Io.Writer,
allocator: Allocator, allocator: Allocator,
registry: *const reg.Registry, registry: *const reg.Registry,
id_renderer: *IdRenderer, id_renderer: *IdRenderer,
@@ -383,7 +381,7 @@ fn Renderer(comptime WriterType: type) type {
have_video: bool, have_video: bool,
fn init( fn init(
writer: WriterType, writer: *std.Io.Writer,
allocator: Allocator, allocator: Allocator,
registry: *const reg.Registry, registry: *const reg.Registry,
id_renderer: *IdRenderer, id_renderer: *IdRenderer,
@@ -2115,16 +2113,15 @@ fn Renderer(comptime WriterType: type) type {
} }
} }
}; };
}
pub fn render( pub fn render(
writer: anytype, writer: *std.Io.Writer,
allocator: Allocator, allocator: Allocator,
registry: *const reg.Registry, registry: *const reg.Registry,
id_renderer: *IdRenderer, id_renderer: *IdRenderer,
have_video: bool, have_video: bool,
) !void { ) !void {
var renderer = try Renderer(@TypeOf(writer)).init(writer, allocator, registry, id_renderer, have_video); var renderer = try Renderer.init(writer, allocator, registry, id_renderer, have_video);
defer renderer.deinit(); defer renderer.deinit();
try renderer.render(); try renderer.render();
} }

View File

@@ -21,9 +21,6 @@ pub const MTLTexture_id = u32;
pub const MTLSharedEvent_id = u32; pub const MTLSharedEvent_id = u32;
pub const IOSurfaceRef = u32; pub const IOSurfaceRef = u32;
// For some reason these types are exported in a different header, and not described in vk.xml.
// If we are not also generating these, the user will have to manually specify them.
pub usingnamespace if (!vk.have_vulkan_video) struct {
pub const StdVideoH264ProfileIdc = u32; pub const StdVideoH264ProfileIdc = u32;
pub const StdVideoH264LevelIdc = u32; pub const StdVideoH264LevelIdc = u32;
pub const StdVideoH264ChromaFormatIdc = u32; pub const StdVideoH264ChromaFormatIdc = u32;
@@ -94,7 +91,6 @@ pub usingnamespace if (!vk.have_vulkan_video) struct {
pub const StdVideoEncodeH265ReferenceInfoFlags = u32; pub const StdVideoEncodeH265ReferenceInfoFlags = u32;
pub const StdVideoEncodeH265ReferenceModificationFlags = u32; pub const StdVideoEncodeH265ReferenceModificationFlags = u32;
pub const StdVideoEncodeAV1OperatingPointInfo = u32; pub const StdVideoEncodeAV1OperatingPointInfo = u32;
} else struct {};
comptime { comptime {
@setEvalBranchQuota(1000000); @setEvalBranchQuota(1000000);