3 Commits

Author SHA1 Message Date
Robin Voetter
2be3eefdfe Merge pull request #197 from mozbeel/android-fix
isARM -> isArm
2025-08-01 00:23:48 +02:00
mozbeel
17ddd01e42 isARM -> isArm 2025-08-01 00:22:02 +02:00
Robin Voetter
2846d415d8 Add workaround for incorrect StdVideoH265HrdParameters encoding
See https://github.com/KhronosGroup/Vulkan-Docs/issues/2557
2025-07-20 08:39:16 +02:00
15 changed files with 1901 additions and 1975 deletions

View File

@@ -7,19 +7,15 @@ 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_module = root_module, .root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}); });
b.installArtifact(generator_exe); b.installArtifact(generator_exe);
@@ -51,16 +47,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(.{ .root_module = root_module }); const test_target = b.addTest(.{
.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

@@ -2,7 +2,7 @@
.name = .vulkan, .name = .vulkan,
.fingerprint = 0xbe155a03c72db6af, .fingerprint = 0xbe155a03c72db6af,
.version = "0.0.0", .version = "0.0.0",
.minimum_zig_version = "0.15.1", .minimum_zig_version = "0.14.0-dev.1359+e9a00ba7f",
.paths = .{ .paths = .{
"build.zig", "build.zig",
"LICENSE", "LICENSE",

View File

@@ -12,14 +12,10 @@ 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");
@@ -37,18 +33,17 @@ 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 = .spirv32, .cpu_arch = .spirv64,
.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(
@@ -58,10 +53,8 @@ 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

@@ -35,7 +35,6 @@ pub const GraphicsContext = struct {
vkb: BaseWrapper, vkb: BaseWrapper,
instance: Instance, instance: Instance,
debug_messenger: vk.DebugUtilsMessengerEXT,
surface: vk.SurfaceKHR, surface: vk.SurfaceKHR,
pdev: vk.PhysicalDevice, pdev: vk.PhysicalDevice,
props: vk.PhysicalDeviceProperties, props: vk.PhysicalDeviceProperties,
@@ -50,17 +49,16 @@ pub const GraphicsContext = struct {
self.allocator = allocator; self.allocator = allocator;
self.vkb = BaseWrapper.load(c.glfwGetInstanceProcAddress); self.vkb = BaseWrapper.load(c.glfwGetInstanceProcAddress);
var extension_names: std.ArrayList([*:0]const u8) = .empty; var extension_names = std.ArrayList([*:0]const u8).init(allocator);
defer extension_names.deinit(allocator); defer extension_names.deinit();
try extension_names.append(allocator, vk.extensions.ext_debug_utils.name); // these extensions are to support vulkan in mac os
// the following extensions are to support vulkan in mac os
// see https://github.com/glfw/glfw/issues/2335 // see https://github.com/glfw/glfw/issues/2335
try extension_names.append(allocator, vk.extensions.khr_portability_enumeration.name); try extension_names.append("VK_KHR_portability_enumeration");
try extension_names.append(allocator, vk.extensions.khr_get_physical_device_properties_2.name); try extension_names.append("VK_KHR_get_physical_device_properties2");
var glfw_exts_count: u32 = 0; var glfw_exts_count: u32 = 0;
const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count); const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count);
try extension_names.appendSlice(allocator, @ptrCast(glfw_exts[0..glfw_exts_count])); try extension_names.appendSlice(@ptrCast(glfw_exts[0..glfw_exts_count]));
const instance = try self.vkb.createInstance(&.{ const instance = try self.vkb.createInstance(&.{
.p_application_info = &.{ .p_application_info = &.{
@@ -83,22 +81,6 @@ pub const GraphicsContext = struct {
self.instance = Instance.init(instance, vki); self.instance = Instance.init(instance, vki);
errdefer self.instance.destroyInstance(null); errdefer self.instance.destroyInstance(null);
self.debug_messenger = try self.instance.createDebugUtilsMessengerEXT(&.{
.message_severity = .{
//.verbose_bit_ext = true,
//.info_bit_ext = true,
.warning_bit_ext = true,
.error_bit_ext = true,
},
.message_type = .{
.general_bit_ext = true,
.validation_bit_ext = true,
.performance_bit_ext = true,
},
.pfn_user_callback = &debugUtilsMessengerCallback,
.p_user_data = null,
}, null);
self.surface = try createSurface(self.instance, window); self.surface = try createSurface(self.instance, window);
errdefer self.instance.destroySurfaceKHR(self.surface, null); errdefer self.instance.destroySurfaceKHR(self.surface, null);
@@ -125,7 +107,6 @@ pub const GraphicsContext = struct {
pub fn deinit(self: GraphicsContext) void { pub fn deinit(self: GraphicsContext) void {
self.dev.destroyDevice(null); self.dev.destroyDevice(null);
self.instance.destroySurfaceKHR(self.surface, null); self.instance.destroySurfaceKHR(self.surface, null);
self.instance.destroyDebugUtilsMessengerEXT(self.debug_messenger, null);
self.instance.destroyInstance(null); self.instance.destroyInstance(null);
// Don't forget to free the tables to prevent a memory leak. // Don't forget to free the tables to prevent a memory leak.
@@ -215,17 +196,6 @@ const QueueAllocation = struct {
present_family: u32, present_family: u32,
}; };
fn debugUtilsMessengerCallback(severity: vk.DebugUtilsMessageSeverityFlagsEXT, msg_type: vk.DebugUtilsMessageTypeFlagsEXT, callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, _: ?*anyopaque) callconv(.c) vk.Bool32 {
const severity_str = if (severity.verbose_bit_ext) "verbose" else if (severity.info_bit_ext) "info" else if (severity.warning_bit_ext) "warning" else if (severity.error_bit_ext) "error" else "unknown";
const type_str = if (msg_type.general_bit_ext) "general" else if (msg_type.validation_bit_ext) "validation" else if (msg_type.performance_bit_ext) "performance" else if (msg_type.device_address_binding_bit_ext) "device addr" else "unknown";
const message: [*c]const u8 = if (callback_data) |cb_data| cb_data.p_message else "NO MESSAGE!";
std.debug.print("[{s}][{s}]. Message:\n {s}\n", .{ severity_str, type_str, message });
return .false;
}
fn pickPhysicalDevice( fn pickPhysicalDevice(
instance: Instance, instance: Instance,
allocator: Allocator, allocator: Allocator,
@@ -283,7 +253,7 @@ fn allocateQueues(instance: Instance, pdev: vk.PhysicalDevice, allocator: Alloca
graphics_family = family; graphics_family = family;
} }
if (present_family == null and (try instance.getPhysicalDeviceSurfaceSupportKHR(pdev, family, surface)) == .true) { if (present_family == null and (try instance.getPhysicalDeviceSurfaceSupportKHR(pdev, family, surface)) == vk.TRUE) {
present_family = family; present_family = family;
} }
} }

View File

@@ -8,5 +8,6 @@ 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);
f_color = .{ v_color[0], v_color[1], v_color[2], 1.0 }; const temp: @Vector(4, f32) = .{ v_color[0], v_color[1], v_color[2], 1.0 };
f_color = temp;
} }

View File

@@ -60,7 +60,7 @@ pub const Swapchain = struct {
.pre_transform = caps.current_transform, .pre_transform = caps.current_transform,
.composite_alpha = .{ .opaque_bit_khr = true }, .composite_alpha = .{ .opaque_bit_khr = true },
.present_mode = present_mode, .present_mode = present_mode,
.clipped = .true, .clipped = vk.TRUE,
.old_swapchain = old_handle, .old_swapchain = old_handle,
}, null) catch { }, null) catch {
return error.SwapchainCreationFailed; return error.SwapchainCreationFailed;
@@ -261,7 +261,7 @@ const SwapImage = struct {
} }
fn waitForFence(self: SwapImage, gc: *const GraphicsContext) !void { fn waitForFence(self: SwapImage, gc: *const GraphicsContext) !void {
_ = try gc.dev.waitForFences(1, @ptrCast(&self.frame_fence), .true, std.math.maxInt(u64)); _ = try gc.dev.waitForFences(1, @ptrCast(&self.frame_fence), vk.TRUE, std.math.maxInt(u64));
} }
}; };

View File

@@ -63,23 +63,6 @@ pub fn main() !void {
) orelse return error.WindowInitFailed; ) orelse return error.WindowInitFailed;
defer c.glfwDestroyWindow(window); defer c.glfwDestroyWindow(window);
// According to the GLFW docs:
//
// > Window systems put limits on window sizes. Very large or very small window dimensions
// > may be overridden by the window system on creation. Check the actual size after creation.
// -- https://www.glfw.org/docs/3.3/group__window.html#ga3555a418df92ad53f917597fe2f64aeb
//
// This happens in practice, for example, when using Wayland with a scaling factor that is not a
// divisor of the initial window size (see https://github.com/Snektron/vulkan-zig/pull/192).
// To fix it, just fetch the actual size here, after the windowing system has had the time to
// update the window.
extent.width, extent.height = blk: {
var w: c_int = undefined;
var h: c_int = undefined;
c.glfwGetFramebufferSize(window, &w, &h);
break :blk .{ @intCast(w), @intCast(h) };
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); defer _ = gpa.deinit();
const allocator = gpa.allocator(); const allocator = gpa.allocator();
@@ -140,7 +123,6 @@ pub fn main() !void {
); );
defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs); defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
var state: Swapchain.PresentState = .optimal;
while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) { while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) {
var w: c_int = undefined; var w: c_int = undefined;
var h: c_int = undefined; var h: c_int = undefined;
@@ -154,6 +136,11 @@ pub fn main() !void {
const cmdbuf = cmdbufs[swapchain.image_index]; const cmdbuf = cmdbufs[swapchain.image_index];
const state = swapchain.present(cmdbuf) catch |err| switch (err) {
error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
else => |narrow| return narrow,
};
if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) { if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) {
extent.width = @intCast(w); extent.width = @intCast(w);
extent.height = @intCast(h); extent.height = @intCast(h);
@@ -174,10 +161,6 @@ pub fn main() !void {
framebuffers, framebuffers,
); );
} }
state = swapchain.present(cmdbuf) catch |err| switch (err) {
error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
else => |narrow| return narrow,
};
c.glfwPollEvents(); c.glfwPollEvents();
} }
@@ -414,7 +397,7 @@ fn createPipeline(
const piasci = vk.PipelineInputAssemblyStateCreateInfo{ const piasci = vk.PipelineInputAssemblyStateCreateInfo{
.topology = .triangle_list, .topology = .triangle_list,
.primitive_restart_enable = .false, .primitive_restart_enable = vk.FALSE,
}; };
const pvsci = vk.PipelineViewportStateCreateInfo{ const pvsci = vk.PipelineViewportStateCreateInfo{
@@ -425,12 +408,12 @@ fn createPipeline(
}; };
const prsci = vk.PipelineRasterizationStateCreateInfo{ const prsci = vk.PipelineRasterizationStateCreateInfo{
.depth_clamp_enable = .false, .depth_clamp_enable = vk.FALSE,
.rasterizer_discard_enable = .false, .rasterizer_discard_enable = vk.FALSE,
.polygon_mode = .fill, .polygon_mode = .fill,
.cull_mode = .{ .back_bit = true }, .cull_mode = .{ .back_bit = true },
.front_face = .clockwise, .front_face = .clockwise,
.depth_bias_enable = .false, .depth_bias_enable = vk.FALSE,
.depth_bias_constant_factor = 0, .depth_bias_constant_factor = 0,
.depth_bias_clamp = 0, .depth_bias_clamp = 0,
.depth_bias_slope_factor = 0, .depth_bias_slope_factor = 0,
@@ -439,14 +422,14 @@ fn createPipeline(
const pmsci = vk.PipelineMultisampleStateCreateInfo{ const pmsci = vk.PipelineMultisampleStateCreateInfo{
.rasterization_samples = .{ .@"1_bit" = true }, .rasterization_samples = .{ .@"1_bit" = true },
.sample_shading_enable = .false, .sample_shading_enable = vk.FALSE,
.min_sample_shading = 1, .min_sample_shading = 1,
.alpha_to_coverage_enable = .false, .alpha_to_coverage_enable = vk.FALSE,
.alpha_to_one_enable = .false, .alpha_to_one_enable = vk.FALSE,
}; };
const pcbas = vk.PipelineColorBlendAttachmentState{ const pcbas = vk.PipelineColorBlendAttachmentState{
.blend_enable = .false, .blend_enable = vk.FALSE,
.src_color_blend_factor = .one, .src_color_blend_factor = .one,
.dst_color_blend_factor = .zero, .dst_color_blend_factor = .zero,
.color_blend_op = .add, .color_blend_op = .add,
@@ -457,7 +440,7 @@ fn createPipeline(
}; };
const pcbsci = vk.PipelineColorBlendStateCreateInfo{ const pcbsci = vk.PipelineColorBlendStateCreateInfo{
.logic_op_enable = .false, .logic_op_enable = vk.FALSE,
.logic_op = .copy, .logic_op = .copy,
.attachment_count = 1, .attachment_count = 1,
.p_attachments = @ptrCast(&pcbas), .p_attachments = @ptrCast(&pcbas),

View File

@@ -52,8 +52,13 @@ pub fn isZigPrimitiveType(name: []const u8) bool {
return false; return false;
} }
pub fn writeIdentifier(w: *std.Io.Writer, id: []const u8) !void { pub fn writeIdentifier(writer: anytype, id: []const u8) !void {
try w.print("{f}", .{std.zig.fmtId(id)}); // https://github.com/ziglang/zig/issues/2897
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 {
@@ -121,12 +126,12 @@ pub const SegmentIterator = struct {
pub const IdRenderer = struct { pub const IdRenderer = struct {
tags: []const []const u8, tags: []const []const u8,
text_cache: std.Io.Writer.Allocating, text_cache: std.ArrayList(u8),
pub fn init(allocator: Allocator, tags: []const []const u8) IdRenderer { pub fn init(allocator: Allocator, tags: []const []const u8) IdRenderer {
return .{ return .{
.tags = tags, .tags = tags,
.text_cache = .init(allocator), .text_cache = std.ArrayList(u8).init(allocator),
}; };
} }
@@ -142,19 +147,19 @@ pub const IdRenderer = struct {
if (first) { if (first) {
first = false; first = false;
} else { } else {
try self.text_cache.writer.writeByte('_'); try self.text_cache.append('_');
} }
for (segment) |c| { for (segment) |c| {
try self.text_cache.writer.writeByte(if (screaming) std.ascii.toUpper(c) else std.ascii.toLower(c)); try self.text_cache.append(if (screaming) std.ascii.toUpper(c) else std.ascii.toLower(c));
} }
} }
if (tag) |name| { if (tag) |name| {
try self.text_cache.writer.writeByte('_'); try self.text_cache.append('_');
for (name) |c| { for (name) |c| {
try self.text_cache.writer.writeByte(if (screaming) std.ascii.toUpper(c) else std.ascii.toLower(c)); try self.text_cache.append(if (screaming) std.ascii.toUpper(c) else std.ascii.toLower(c));
} }
} }
} }
@@ -166,7 +171,7 @@ pub const IdRenderer = struct {
while (it.next()) |segment| { while (it.next()) |segment| {
var i: usize = 0; var i: usize = 0;
while (i < segment.len and std.ascii.isDigit(segment[i])) { while (i < segment.len and std.ascii.isDigit(segment[i])) {
try self.text_cache.writer.writeByte(segment[i]); try self.text_cache.append(segment[i]);
i += 1; i += 1;
} }
@@ -175,34 +180,34 @@ pub const IdRenderer = struct {
} }
if (i == 0 and lower_first) { if (i == 0 and lower_first) {
try self.text_cache.writer.writeByte(std.ascii.toLower(segment[i])); try self.text_cache.append(std.ascii.toLower(segment[i]));
} else { } else {
try self.text_cache.writer.writeByte(std.ascii.toUpper(segment[i])); try self.text_cache.append(std.ascii.toUpper(segment[i]));
} }
lower_first = false; lower_first = false;
for (segment[i + 1 ..]) |c| { for (segment[i + 1 ..]) |c| {
try self.text_cache.writer.writeByte(std.ascii.toLower(c)); try self.text_cache.append(std.ascii.toLower(c));
} }
} }
if (tag) |name| { if (tag) |name| {
try self.text_cache.writer.writeAll(name); try self.text_cache.appendSlice(name);
} }
} }
pub fn renderFmt(self: *IdRenderer, out: *std.Io.Writer, comptime fmt: []const u8, args: anytype) !void { pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void {
_ = self.text_cache.writer.consumeAll(); self.text_cache.items.len = 0;
try self.text_cache.writer.print(fmt, args); try std.fmt.format(self.text_cache.writer(), fmt, args);
try writeIdentifier(out, self.text_cache.writer.buffered()); try writeIdentifier(out, self.text_cache.items);
} }
pub fn renderWithCase(self: *IdRenderer, out: *std.Io.Writer, case_style: CaseStyle, id: []const u8) !void { pub fn renderWithCase(self: *IdRenderer, out: anytype, 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;
_ = self.text_cache.writer.consumeAll(); self.text_cache.items.len = 0;
switch (case_style) { switch (case_style) {
.snake => try self.renderSnake(false, adjusted_id, tag), .snake => try self.renderSnake(false, adjusted_id, tag),
@@ -211,7 +216,7 @@ pub const IdRenderer = struct {
.camel => try self.renderCamel(false, adjusted_id, tag), .camel => try self.renderCamel(false, adjusted_id, tag),
} }
try writeIdentifier(out, self.text_cache.writer.buffered()); try writeIdentifier(out, self.text_cache.items);
} }
pub fn getAuthorTag(self: IdRenderer, id: []const u8) ?[]const u8 { pub fn getAuthorTag(self: IdRenderer, id: []const u8) ?[]const u8 {

View File

@@ -1,5 +1,4 @@
const std = @import("std"); const std = @import("std");
const generator = @import("vulkan/generator.zig"); const generator = @import("vulkan/generator.zig");
fn invalidUsage(prog_name: []const u8, comptime fmt: []const u8, args: anytype) noreturn { fn invalidUsage(prog_name: []const u8, comptime fmt: []const u8, args: anytype) noreturn {
@@ -9,32 +8,27 @@ 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 {
var buf: [1024]u8 = undefined; const stderr = std.io.getStdErr().writer();
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 w.print("(vulkan-zig error):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 }); try stderr.print("(vulkan-zig error):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
try tree.renderError(err, w); try tree.renderError(err, stderr);
try w.print("\n{s}\n", .{tree.source[loc.line_start..loc.line_end]}); try stderr.print("\n{s}\n", .{tree.source[loc.line_start..loc.line_end]});
for (0..loc.column) |_| { for (0..loc.column) |_| {
try w.writeAll(" "); try stderr.writeAll(" ");
} }
try w.writeAll("^\n"); try stderr.writeAll("^\n");
} }
} }
fn oomPanic() noreturn {
@panic("Out of memory");
}
pub fn main() !void { pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
const allocator = arena.allocator(); const allocator = arena.allocator();
var args = std.process.argsWithAllocator(allocator) catch |err| switch (err) { var args = std.process.argsWithAllocator(allocator) catch |err| switch (err) {
error.OutOfMemory => oomPanic(), error.OutOfMemory => @panic("OOM"),
}; };
const prog_name = args.next() orelse "vulkan-zig-generator"; const prog_name = args.next() orelse "vulkan-zig-generator";
@@ -47,9 +41,7 @@ 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);
var buf: [1024]u8 = undefined; std.io.getStdOut().writer().print(
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
@@ -68,7 +60,8 @@ pub fn main() !void {
, ,
.{prog_name}, .{prog_name},
) catch |err| { ) catch |err| {
std.process.fatal("failed to write to stdout: {s}", .{@errorName(err)}); std.log.err("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")) {
@@ -102,24 +95,21 @@ pub fn main() !void {
}; };
const cwd = std.fs.cwd(); const cwd = std.fs.cwd();
const xml_src = cwd.readFileAlloc(xml_path, allocator, .unlimited) catch |err| { const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| {
std.process.fatal("failed to open input file '{s}' ({s})", .{ xml_path, @errorName(err) }); std.log.err("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(video_xml_path, allocator, .unlimited) catch |err| { cwd.readFileAlloc(allocator, video_xml_path, std.math.maxInt(usize)) catch |err| {
std.process.fatal("failed to open input file '{s}' ({s})", .{ video_xml_path, @errorName(err) }); std.log.err("failed to open input file '{s}' ({s})", .{ video_xml_path, @errorName(err) });
std.process.exit(1);
} }
else else
null; null;
var aw: std.Io.Writer.Allocating = .init(allocator); var out_buffer = std.ArrayList(u8).init(allocator);
generator.generate(allocator, api, xml_src, maybe_video_xml_src, &aw.writer) catch |err| { generator.generate(allocator, api, xml_src, maybe_video_xml_src, out_buffer.writer()) catch |err| switch (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", .{});
@@ -136,16 +126,14 @@ 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, error.WriteFailed => oomPanic(), error.OutOfMemory => @panic("oom"),
}
}; };
aw.writer.writeByte(0) catch oomPanic(); out_buffer.append(0) catch @panic("oom");
const buffered = aw.writer.buffered(); const src = out_buffer.items[0 .. out_buffer.items.len - 1 :0];
const src = buffered[0 .. buffered.len - 1 :0];
const tree = std.zig.Ast.parse(allocator, src, .zig) catch |err| switch (err) { const tree = std.zig.Ast.parse(allocator, src, .zig) catch |err| switch (err) {
error.OutOfMemory => oomPanic(), error.OutOfMemory => @panic("oom"),
}; };
const formatted = if (tree.errors.len > 0) blk: { const formatted = if (tree.errors.len > 0) blk: {
@@ -155,20 +143,22 @@ 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.process.fatal("failed to dump ast errors: {s}", .{@errorName(err)}); std.log.err("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.renderAlloc(allocator) catch |err| switch (err) { } else tree.render(allocator) catch |err| switch (err) {
error.OutOfMemory => oomPanic(), 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.process.fatal("failed to create output directory '{s}' ({s})", .{ dir, @errorName(err) }); std.log.err("failed to create output directory '{s}' ({s})", .{ dir, @errorName(err) });
std.process.exit(1);
}; };
} }
@@ -176,7 +166,8 @@ pub fn main() !void {
.sub_path = out_path, .sub_path = out_path,
.data = formatted, .data = formatted,
}) catch |err| { }) catch |err| {
std.process.fatal("failed to write to output file '{s}' ({s})", .{ out_path, @errorName(err) }); std.log.err("failed to write to output file '{s}' ({s})", .{ out_path, @errorName(err) });
std.process.exit(1);
}; };
} }

View File

@@ -457,8 +457,8 @@ fn parseFnPtrSuffix(allocator: Allocator, xctok: *XmlCTokenizer, return_type: Ty
// There is no good way to estimate the number of parameters beforehand. // There is no good way to estimate the number of parameters beforehand.
// Fortunately, there are usually a relatively low number of parameters to a function pointer, // Fortunately, there are usually a relatively low number of parameters to a function pointer,
// so an ArrayList backed by an arena allocator is good enough. // so an ArrayList backed by an arena allocator is good enough.
var params: std.ArrayList(registry.Command.Param) = .empty; var params = std.ArrayList(registry.Command.Param).init(allocator);
try params.append(allocator, .{ try params.append(.{
.name = first_param.name.?, .name = first_param.name.?,
.param_type = first_param.decl_type, .param_type = first_param.decl_type,
.is_buffer_len = false, .is_buffer_len = false,
@@ -473,7 +473,7 @@ fn parseFnPtrSuffix(allocator: Allocator, xctok: *XmlCTokenizer, return_type: Ty
} }
const decl = try parseDeclaration(allocator, xctok, ptrs_optional); const decl = try parseDeclaration(allocator, xctok, ptrs_optional);
try params.append(allocator, .{ try params.append(.{
.name = decl.name orelse return error.MissingTypeIdentifier, .name = decl.name orelse return error.MissingTypeIdentifier,
.param_type = decl.decl_type, .param_type = decl.decl_type,
.is_buffer_len = false, .is_buffer_len = false,
@@ -482,7 +482,7 @@ fn parseFnPtrSuffix(allocator: Allocator, xctok: *XmlCTokenizer, return_type: Ty
} }
_ = try xctok.nextNoEof(); _ = try xctok.nextNoEof();
command_ptr.decl_type.command_ptr.params = try params.toOwnedSlice(allocator); command_ptr.decl_type.command_ptr.params = try params.toOwnedSlice();
return command_ptr; return command_ptr;
} }

View File

@@ -32,7 +32,7 @@ const EnumFieldMerger = struct {
fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void { fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void {
const res = try self.enum_extensions.getOrPut(self.arena, enum_name); const res = try self.enum_extensions.getOrPut(self.arena, enum_name);
if (!res.found_existing) { if (!res.found_existing) {
res.value_ptr.* = .empty; res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){};
} }
try res.value_ptr.append(self.arena, field); try res.value_ptr.append(self.arena, field);
@@ -186,7 +186,7 @@ pub const Generator = struct {
self.registry.decls.len = i; self.registry.decls.len = i;
} }
fn render(self: *Generator, writer: *std.Io.Writer) !void { fn render(self: *Generator, writer: anytype) !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: *std.Io.Writer, writer: anytype,
) !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

@@ -28,11 +28,11 @@ pub fn parseXml(
const allocator = arena.allocator(); const allocator = arena.allocator();
var decls: std.ArrayList(registry.Declaration) = .empty; var decls: std.ArrayListUnmanaged(registry.Declaration) = .{};
var api_constants: std.ArrayList(registry.ApiConstant) = .empty; var api_constants: std.ArrayListUnmanaged(registry.ApiConstant) = .{};
var tags: std.ArrayList(registry.Tag) = .empty; var tags: std.ArrayListUnmanaged(registry.Tag) = .{};
var features: std.ArrayList(registry.Feature) = .empty; var features: std.ArrayListUnmanaged(registry.Feature) = .{};
var extensions: std.ArrayList(registry.Extension) = .empty; var extensions: std.ArrayListUnmanaged(registry.Extension) = .{};
try parseDeclarations(allocator, root, api, &decls); try parseDeclarations(allocator, root, api, &decls);
try parseApiConstants(allocator, root, api, &api_constants); try parseApiConstants(allocator, root, api, &api_constants);
@@ -66,7 +66,7 @@ fn parseDeclarations(
allocator: Allocator, allocator: Allocator,
root: *xml.Element, root: *xml.Element,
api: registry.Api, api: registry.Api,
decls: *std.ArrayList(registry.Declaration), decls: *std.ArrayListUnmanaged(registry.Declaration),
) !void { ) !void {
const types_elem = root.findChildByTag("types") orelse return error.InvalidRegistry; const types_elem = root.findChildByTag("types") orelse return error.InvalidRegistry;
try decls.ensureUnusedCapacity(allocator, types_elem.children.len); try decls.ensureUnusedCapacity(allocator, types_elem.children.len);
@@ -84,7 +84,7 @@ fn parseTypes(
allocator: Allocator, allocator: Allocator,
types_elem: *xml.Element, types_elem: *xml.Element,
api: registry.Api, api: registry.Api,
decls: *std.ArrayList(registry.Declaration), decls: *std.ArrayListUnmanaged(registry.Declaration),
) !void { ) !void {
var it = types_elem.findChildrenByTag("type"); var it = types_elem.findChildrenByTag("type");
while (it.next()) |ty| { while (it.next()) |ty| {
@@ -429,7 +429,7 @@ fn parseEnums(
allocator: Allocator, allocator: Allocator,
root: *xml.Element, root: *xml.Element,
api: registry.Api, api: registry.Api,
decls: *std.ArrayList(registry.Declaration), decls: *std.ArrayListUnmanaged(registry.Declaration),
) !void { ) !void {
var it = root.findChildrenByTag("enums"); var it = root.findChildrenByTag("enums");
while (it.next()) |enums| { while (it.next()) |enums| {
@@ -519,7 +519,7 @@ fn parseCommands(
allocator: Allocator, allocator: Allocator,
commands_elem: *xml.Element, commands_elem: *xml.Element,
api: registry.Api, api: registry.Api,
decls: *std.ArrayList(registry.Declaration), decls: *std.ArrayListUnmanaged(registry.Declaration),
) !void { ) !void {
var it = commands_elem.findChildrenByTag("command"); var it = commands_elem.findChildrenByTag("command");
while (it.next()) |elem| { while (it.next()) |elem| {
@@ -630,7 +630,7 @@ fn parseApiConstants(
allocator: Allocator, allocator: Allocator,
root: *xml.Element, root: *xml.Element,
api: registry.Api, api: registry.Api,
api_constants: *std.ArrayList(registry.ApiConstant), api_constants: *std.ArrayListUnmanaged(registry.ApiConstant),
) !void { ) !void {
const maybe_enums = blk: { const maybe_enums = blk: {
var it = root.findChildrenByTag("enums"); var it = root.findChildrenByTag("enums");
@@ -672,7 +672,7 @@ fn parseDefines(
allocator: Allocator, allocator: Allocator,
types: *xml.Element, types: *xml.Element,
api: registry.Api, api: registry.Api,
api_constants: *std.ArrayList(registry.ApiConstant), api_constants: *std.ArrayListUnmanaged(registry.ApiConstant),
) !void { ) !void {
var it = types.findChildrenByTag("type"); var it = types.findChildrenByTag("type");
while (it.next()) |ty| { while (it.next()) |ty| {
@@ -703,7 +703,7 @@ fn parseDefines(
fn parseTags( fn parseTags(
allocator: Allocator, allocator: Allocator,
root: *xml.Element, root: *xml.Element,
tags: *std.ArrayList(registry.Tag), tags: *std.ArrayListUnmanaged(registry.Tag),
) !void { ) !void {
var tags_elem = root.findChildByTag("tags") orelse return; var tags_elem = root.findChildByTag("tags") orelse return;
try tags.ensureUnusedCapacity(allocator, tags_elem.children.len); try tags.ensureUnusedCapacity(allocator, tags_elem.children.len);
@@ -717,7 +717,7 @@ fn parseTags(
} }
} }
fn parseFeatures(allocator: Allocator, root: *xml.Element, api: registry.Api, features: *std.ArrayList(registry.Feature)) !void { fn parseFeatures(allocator: Allocator, root: *xml.Element, api: registry.Api, features: *std.ArrayListUnmanaged(registry.Feature)) !void {
var it = root.findChildrenByTag("feature"); var it = root.findChildrenByTag("feature");
while (it.next()) |feature| { while (it.next()) |feature| {
if (!requiredByApi(feature, api)) if (!requiredByApi(feature, api))
@@ -881,7 +881,7 @@ fn parseExtensions(
allocator: Allocator, allocator: Allocator,
root: *xml.Element, root: *xml.Element,
api: registry.Api, api: registry.Api,
extensions: *std.ArrayList(registry.Extension), extensions: *std.ArrayListUnmanaged(registry.Extension),
) !void { ) !void {
const extensions_elem = root.findChildByTag("extensions") orelse return error.InvalidRegistry; const extensions_elem = root.findChildByTag("extensions") orelse return error.InvalidRegistry;
try extensions.ensureUnusedCapacity(allocator, extensions_elem.children.len); try extensions.ensureUnusedCapacity(allocator, extensions_elem.children.len);

View File

@@ -1,12 +1,11 @@
const std = @import("std"); const std = @import("std");
const reg = @import("registry.zig");
const id_render = @import("../id_render.zig");
const cparse = @import("c_parse.zig");
const mem = std.mem; const mem = std.mem;
const Allocator = mem.Allocator; const Allocator = mem.Allocator;
const id_render = @import("../id_render.zig");
const CaseStyle = id_render.CaseStyle; const CaseStyle = id_render.CaseStyle;
const IdRenderer = id_render.IdRenderer; const IdRenderer = id_render.IdRenderer;
const cparse = @import("c_parse.zig");
const reg = @import("registry.zig");
const preamble = const preamble =
\\// This file is generated from the Khronos Vulkan XML API registry by vulkan-zig. \\// This file is generated from the Khronos Vulkan XML API registry by vulkan-zig.
@@ -18,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)
\\ .winapi \\ .Stdcall
\\ 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.
\\ .arm_aapcs_vfp \\ .AAPCSVFP
\\ 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 {
@@ -59,6 +58,8 @@ const preamble =
\\ return struct { \\ return struct {
\\ pub fn format( \\ pub fn format(
\\ self: FlagsType, \\ self: FlagsType,
\\ comptime _: []const u8,
\\ _: std.fmt.FormatOptions,
\\ writer: anytype, \\ writer: anytype,
\\ ) !void { \\ ) !void {
\\ try writer.writeAll(@typeName(FlagsType) ++ "{"); \\ try writer.writeAll(@typeName(FlagsType) ++ "{");
@@ -335,9 +336,11 @@ pub fn trimVkNamespace(id: []const u8) []const u8 {
return id; return id;
} }
const Renderer = struct { fn Renderer(comptime WriterType: type) type {
return struct {
const Self = @This(); const Self = @This();
const RenderTypeInfoError = std.Io.Writer.Error || std.fmt.ParseIntError || error{ OutOfMemory, InvalidRegistry }; const WriteError = WriterType.Error;
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
@@ -371,7 +374,7 @@ const Renderer = struct {
}, },
}; };
writer: *std.Io.Writer, writer: WriterType,
allocator: Allocator, allocator: Allocator,
registry: *const reg.Registry, registry: *const reg.Registry,
id_renderer: *IdRenderer, id_renderer: *IdRenderer,
@@ -380,7 +383,7 @@ const Renderer = struct {
have_video: bool, have_video: bool,
fn init( fn init(
writer: *std.Io.Writer, writer: WriterType,
allocator: Allocator, allocator: Allocator,
registry: *const reg.Registry, registry: *const reg.Registry,
id_renderer: *IdRenderer, id_renderer: *IdRenderer,
@@ -848,10 +851,6 @@ const Renderer = struct {
} }
fn renderDecl(self: *Self, decl: reg.Declaration) !void { fn renderDecl(self: *Self, decl: reg.Declaration) !void {
if (try self.renderSpecial(decl.name)) {
return;
}
switch (decl.decl_type) { switch (decl.decl_type) {
.container => |container| try self.renderContainer(decl.name, container), .container => |container| try self.renderContainer(decl.name, container),
.enumeration => |enumeration| try self.renderEnumeration(decl.name, enumeration), .enumeration => |enumeration| try self.renderEnumeration(decl.name, enumeration),
@@ -865,27 +864,10 @@ const Renderer = struct {
} }
} }
fn renderAssign(self: *Self, name: []const u8) !void { fn renderSpecialContainer(self: *Self, name: []const u8) !bool {
try self.writer.writeAll("pub const ");
try self.renderName(name);
try self.writer.writeAll(" = ");
}
fn renderSpecial(self: *Self, name: []const u8) !bool {
const maybe_author = self.id_renderer.getAuthorTag(name); const maybe_author = self.id_renderer.getAuthorTag(name);
const basename = self.id_renderer.stripAuthorTag(name); const basename = self.id_renderer.stripAuthorTag(name);
if (std.mem.eql(u8, basename, "VkBool32")) { if (std.mem.eql(u8, basename, "VkAccelerationStructureInstance")) {
try self.renderAssign(name);
try self.writer.writeAll(
\\enum(i32) {
\\ false,
\\ true,
\\ _,
\\};
\\
);
} else if (std.mem.eql(u8, basename, "VkAccelerationStructureInstance")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ transform: TransformMatrix{s}, \\ transform: TransformMatrix{s},
@@ -903,8 +885,8 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
return true;
} else if (std.mem.eql(u8, basename, "VkAccelerationStructureSRTMotionInstance")) { } else if (std.mem.eql(u8, basename, "VkAccelerationStructureSRTMotionInstance")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ transform_t0: SRTData{0s}, \\ transform_t0: SRTData{0s},
@@ -923,8 +905,8 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
return true;
} else if (std.mem.eql(u8, basename, "VkAccelerationStructureMatrixMotionInstance")) { } else if (std.mem.eql(u8, basename, "VkAccelerationStructureMatrixMotionInstance")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ transform_t0: TransformMatrix{0s}, \\ transform_t0: TransformMatrix{0s},
@@ -943,8 +925,8 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
return true;
} else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureBuildTriangleClusterInfo")) { } else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureBuildTriangleClusterInfo")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ cluster_id: u32, \\ cluster_id: u32,
@@ -970,8 +952,8 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
return true;
} else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureBuildTriangleClusterTemplateInfo")) { } else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureBuildTriangleClusterTemplateInfo")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ cluster_id: u32, \\ cluster_id: u32,
@@ -998,8 +980,8 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
return true;
} else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureInstantiateClusterInfo")) { } else if (std.mem.eql(u8, basename, "VkClusterAccelerationStructureInstantiateClusterInfo")) {
try self.renderAssign(name);
try self.writer.print( try self.writer.print(
\\extern struct {{ \\extern struct {{
\\ cluster_id_offset: u32, \\ cluster_id_offset: u32,
@@ -1013,11 +995,10 @@ const Renderer = struct {
, ,
.{maybe_author orelse ""}, .{maybe_author orelse ""},
); );
} else { return true;
return false;
} }
return true; return false;
} }
fn renderSimpleBitContainer(self: *Self, container: reg.Container) !bool { fn renderSimpleBitContainer(self: *Self, container: reg.Container) !bool {
@@ -1073,6 +1054,10 @@ const Renderer = struct {
return; return;
} }
if (try self.renderSpecialContainer(name)) {
return;
}
for (container.fields) |field| { for (container.fields) |field| {
if (field.bits != null) { if (field.bits != null) {
return error.UnhandledBitfieldStruct; return error.UnhandledBitfieldStruct;
@@ -1127,7 +1112,7 @@ const Renderer = struct {
try self.writer.writeAll(" = ."); try self.writer.writeAll(" = .");
try self.writeIdentifierWithCase(.snake, stype["VK_STRUCTURE_TYPE_".len..]); try self.writeIdentifierWithCase(.snake, stype["VK_STRUCTURE_TYPE_".len..]);
} else if (field.field_type == .name and mem.eql(u8, "VkBool32", field.field_type.name) and isFeatureStruct(name, container.extends)) { } else if (field.field_type == .name and mem.eql(u8, "VkBool32", field.field_type.name) and isFeatureStruct(name, container.extends)) {
try self.writer.writeAll(" = .false"); try self.writer.writeAll(" = FALSE");
} else if (field.is_optional) { } else if (field.is_optional) {
if (field.field_type == .name) { if (field.field_type == .name) {
const field_type_name = field.field_type.name; const field_type_name = field.field_type.name;
@@ -1138,8 +1123,6 @@ const Renderer = struct {
try self.writer.writeAll(" = .{}"); try self.writer.writeAll(" = .{}");
} else if (decl_type == .typedef and decl_type.typedef == .command_ptr) { } else if (decl_type == .typedef and decl_type.typedef == .command_ptr) {
try self.writer.writeAll(" = null"); try self.writer.writeAll(" = null");
} else if (mem.eql(u8, "VkBool32", field.field_type.name)) {
try self.writer.writeAll(" = .false");
} else if ((decl_type == .typedef and builtin_types.has(decl_type.typedef.name)) or } else if ((decl_type == .typedef and builtin_types.has(decl_type.typedef.name)) or
(decl_type == .foreign and builtin_types.has(field_type_name))) (decl_type == .foreign and builtin_types.has(field_type_name)))
{ {
@@ -1829,13 +1812,12 @@ const Renderer = struct {
} }
fn extractReturns(self: *Self, command: reg.Command) ![]const ReturnValue { fn extractReturns(self: *Self, command: reg.Command) ![]const ReturnValue {
const allocator = self.allocator; var returns = std.ArrayList(ReturnValue).init(self.allocator);
var returns: std.ArrayList(ReturnValue) = .empty;
if (command.return_type.* == .name) { if (command.return_type.* == .name) {
const return_name = command.return_type.name; const return_name = command.return_type.name;
if (!mem.eql(u8, return_name, "void") and !mem.eql(u8, return_name, "VkResult")) { if (!mem.eql(u8, return_name, "void") and !mem.eql(u8, return_name, "VkResult")) {
try returns.append(allocator, .{ try returns.append(.{
.name = "return_value", .name = "return_value",
.return_value_type = command.return_type.*, .return_value_type = command.return_type.*,
.origin = .inner_return_value, .origin = .inner_return_value,
@@ -1848,7 +1830,7 @@ const Renderer = struct {
return error.InvalidRegistry; return error.InvalidRegistry;
} }
try returns.append(allocator, .{ try returns.append(.{
.name = "result", .name = "result",
.return_value_type = command.return_type.*, .return_value_type = command.return_type.*,
.origin = .inner_return_value, .origin = .inner_return_value,
@@ -1859,7 +1841,7 @@ const Renderer = struct {
for (command.params) |param| { for (command.params) |param| {
if ((try self.classifyParam(param)) == .out_pointer) { if ((try self.classifyParam(param)) == .out_pointer) {
try returns.append(allocator, .{ try returns.append(.{
.name = derefName(param.name), .name = derefName(param.name),
.return_value_type = param.param_type.pointer.child.*, .return_value_type = param.param_type.pointer.child.*,
.origin = .parameter, .origin = .parameter,
@@ -1867,7 +1849,7 @@ const Renderer = struct {
} }
} }
return try returns.toOwnedSlice(allocator); return try returns.toOwnedSlice();
} }
fn renderReturnStructName(self: *Self, command_name: []const u8) !void { fn renderReturnStructName(self: *Self, command_name: []const u8) !void {
@@ -2132,16 +2114,17 @@ const Renderer = struct {
try self.writeIdentifierWithCase(.title, trimVkNamespace(name)); try self.writeIdentifierWithCase(.title, trimVkNamespace(name));
} }
} }
}; };
}
pub fn render( pub fn render(
writer: *std.Io.Writer, writer: anytype,
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.init(writer, allocator, registry, id_renderer, have_video); var renderer = try Renderer(@TypeOf(writer)).init(writer, allocator, registry, id_renderer, have_video);
defer renderer.deinit(); defer renderer.deinit();
try renderer.render(); try renderer.render();
} }

View File

@@ -439,15 +439,15 @@ fn parseElement(parser: *Parser, alloc: Allocator, comptime kind: ElementKind) !
}, },
}; };
var attributes: std.ArrayList(Attribute) = .empty; var attributes = std.ArrayList(Attribute).init(alloc);
defer attributes.deinit(alloc); defer attributes.deinit();
var children: std.ArrayList(Content) = .empty; var children = std.ArrayList(Content).init(alloc);
defer children.deinit(alloc); defer children.deinit();
while (parser.eatWs()) { while (parser.eatWs()) {
const attr = (try parseAttr(parser, alloc)) orelse break; const attr = (try parseAttr(parser, alloc)) orelse break;
try attributes.append(alloc, attr); try attributes.append(attr);
} }
switch (kind) { switch (kind) {
@@ -464,7 +464,7 @@ fn parseElement(parser: *Parser, alloc: Allocator, comptime kind: ElementKind) !
} }
const content = try parseContent(parser, alloc); const content = try parseContent(parser, alloc);
try children.append(alloc, content); try children.append(content);
} }
const closing_tag = try parseNameNoDupe(parser); const closing_tag = try parseNameNoDupe(parser);
@@ -481,8 +481,8 @@ fn parseElement(parser: *Parser, alloc: Allocator, comptime kind: ElementKind) !
const element = try alloc.create(Element); const element = try alloc.create(Element);
element.* = .{ element.* = .{
.tag = try alloc.dupe(u8, tag), .tag = try alloc.dupe(u8, tag),
.attributes = try attributes.toOwnedSlice(alloc), .attributes = try attributes.toOwnedSlice(),
.children = try children.toOwnedSlice(alloc), .children = try children.toOwnedSlice(),
}; };
return element; return element;
} }

View File

@@ -21,76 +21,80 @@ pub const MTLTexture_id = u32;
pub const MTLSharedEvent_id = u32; pub const MTLSharedEvent_id = u32;
pub const IOSurfaceRef = u32; pub const IOSurfaceRef = u32;
pub const StdVideoH264ProfileIdc = u32; // For some reason these types are exported in a different header, and not described in vk.xml.
pub const StdVideoH264LevelIdc = u32; // If we are not also generating these, the user will have to manually specify them.
pub const StdVideoH264ChromaFormatIdc = u32; pub usingnamespace if (!vk.have_vulkan_video) struct {
pub const StdVideoH264PocType = u32; pub const StdVideoH264ProfileIdc = u32;
pub const StdVideoH264SpsFlags = u32; pub const StdVideoH264LevelIdc = u32;
pub const StdVideoH264ScalingLists = u32; pub const StdVideoH264ChromaFormatIdc = u32;
pub const StdVideoH264SequenceParameterSetVui = u32; pub const StdVideoH264PocType = u32;
pub const StdVideoH264AspectRatioIdc = u32; pub const StdVideoH264SpsFlags = u32;
pub const StdVideoH264HrdParameters = u32; pub const StdVideoH264ScalingLists = u32;
pub const StdVideoH264SpsVuiFlags = u32; pub const StdVideoH264SequenceParameterSetVui = u32;
pub const StdVideoH264WeightedBipredIdc = u32; pub const StdVideoH264AspectRatioIdc = u32;
pub const StdVideoH264PpsFlags = u32; pub const StdVideoH264HrdParameters = u32;
pub const StdVideoH264SliceType = u32; pub const StdVideoH264SpsVuiFlags = u32;
pub const StdVideoH264CabacInitIdc = u32; pub const StdVideoH264WeightedBipredIdc = u32;
pub const StdVideoH264DisableDeblockingFilterIdc = u32; pub const StdVideoH264PpsFlags = u32;
pub const StdVideoH264PictureType = u32; pub const StdVideoH264SliceType = u32;
pub const StdVideoH264ModificationOfPicNumsIdc = u32; pub const StdVideoH264CabacInitIdc = u32;
pub const StdVideoH264MemMgmtControlOp = u32; pub const StdVideoH264DisableDeblockingFilterIdc = u32;
pub const StdVideoDecodeH264PictureInfo = u32; pub const StdVideoH264PictureType = u32;
pub const StdVideoDecodeH264ReferenceInfo = u32; pub const StdVideoH264ModificationOfPicNumsIdc = u32;
pub const StdVideoDecodeH264PictureInfoFlags = u32; pub const StdVideoH264MemMgmtControlOp = u32;
pub const StdVideoDecodeH264ReferenceInfoFlags = u32; pub const StdVideoDecodeH264PictureInfo = u32;
pub const StdVideoH264SequenceParameterSet = u32; pub const StdVideoDecodeH264ReferenceInfo = u32;
pub const StdVideoH264PictureParameterSet = u32; pub const StdVideoDecodeH264PictureInfoFlags = u32;
pub const StdVideoH265ProfileIdc = u32; pub const StdVideoDecodeH264ReferenceInfoFlags = u32;
pub const StdVideoH265VideoParameterSet = u32; pub const StdVideoH264SequenceParameterSet = u32;
pub const StdVideoH265SequenceParameterSet = u32; pub const StdVideoH264PictureParameterSet = u32;
pub const StdVideoH265PictureParameterSet = u32; pub const StdVideoH265ProfileIdc = u32;
pub const StdVideoH265DecPicBufMgr = u32; pub const StdVideoH265VideoParameterSet = u32;
pub const StdVideoH265HrdParameters = u32; pub const StdVideoH265SequenceParameterSet = u32;
pub const StdVideoH265VpsFlags = u32; pub const StdVideoH265PictureParameterSet = u32;
pub const StdVideoH265LevelIdc = u32; pub const StdVideoH265DecPicBufMgr = u32;
pub const StdVideoH265SpsFlags = u32; pub const StdVideoH265HrdParameters = u32;
pub const StdVideoH265ScalingLists = u32; pub const StdVideoH265VpsFlags = u32;
pub const StdVideoH265SequenceParameterSetVui = u32; pub const StdVideoH265LevelIdc = u32;
pub const StdVideoH265PredictorPaletteEntries = u32; pub const StdVideoH265SpsFlags = u32;
pub const StdVideoH265PpsFlags = u32; pub const StdVideoH265ScalingLists = u32;
pub const StdVideoH265SubLayerHrdParameters = u32; pub const StdVideoH265SequenceParameterSetVui = u32;
pub const StdVideoH265HrdFlags = u32; pub const StdVideoH265PredictorPaletteEntries = u32;
pub const StdVideoH265SpsVuiFlags = u32; pub const StdVideoH265PpsFlags = u32;
pub const StdVideoH265SliceType = u32; pub const StdVideoH265SubLayerHrdParameters = u32;
pub const StdVideoH265PictureType = u32; pub const StdVideoH265HrdFlags = u32;
pub const StdVideoDecodeH265PictureInfo = u32; pub const StdVideoH265SpsVuiFlags = u32;
pub const StdVideoDecodeH265ReferenceInfo = u32; pub const StdVideoH265SliceType = u32;
pub const StdVideoDecodeH265PictureInfoFlags = u32; pub const StdVideoH265PictureType = u32;
pub const StdVideoDecodeH265ReferenceInfoFlags = u32; pub const StdVideoDecodeH265PictureInfo = u32;
pub const StdVideoAV1Profile = u32; pub const StdVideoDecodeH265ReferenceInfo = u32;
pub const StdVideoAV1Level = u32; pub const StdVideoDecodeH265PictureInfoFlags = u32;
pub const StdVideoAV1SequenceHeader = u32; pub const StdVideoDecodeH265ReferenceInfoFlags = u32;
pub const StdVideoDecodeAV1PictureInfo = u32; pub const StdVideoAV1Profile = u32;
pub const StdVideoDecodeAV1ReferenceInfo = u32; pub const StdVideoAV1Level = u32;
pub const StdVideoEncodeH264SliceHeader = u32; pub const StdVideoAV1SequenceHeader = u32;
pub const StdVideoEncodeH264PictureInfo = u32; pub const StdVideoDecodeAV1PictureInfo = u32;
pub const StdVideoEncodeH264ReferenceInfo = u32; pub const StdVideoDecodeAV1ReferenceInfo = u32;
pub const StdVideoEncodeH264SliceHeaderFlags = u32; pub const StdVideoEncodeH264SliceHeader = u32;
pub const StdVideoEncodeH264ReferenceListsInfo = u32; pub const StdVideoEncodeH264PictureInfo = u32;
pub const StdVideoEncodeH264PictureInfoFlags = u32; pub const StdVideoEncodeH264ReferenceInfo = u32;
pub const StdVideoEncodeH264ReferenceInfoFlags = u32; pub const StdVideoEncodeH264SliceHeaderFlags = u32;
pub const StdVideoEncodeH264RefMgmtFlags = u32; pub const StdVideoEncodeH264ReferenceListsInfo = u32;
pub const StdVideoEncodeH264RefListModEntry = u32; pub const StdVideoEncodeH264PictureInfoFlags = u32;
pub const StdVideoEncodeH264RefPicMarkingEntry = u32; pub const StdVideoEncodeH264ReferenceInfoFlags = u32;
pub const StdVideoEncodeH265PictureInfoFlags = u32; pub const StdVideoEncodeH264RefMgmtFlags = u32;
pub const StdVideoEncodeH265PictureInfo = u32; pub const StdVideoEncodeH264RefListModEntry = u32;
pub const StdVideoEncodeH265SliceSegmentHeader = u32; pub const StdVideoEncodeH264RefPicMarkingEntry = u32;
pub const StdVideoEncodeH265ReferenceInfo = u32; pub const StdVideoEncodeH265PictureInfoFlags = u32;
pub const StdVideoEncodeH265ReferenceListsInfo = u32; pub const StdVideoEncodeH265PictureInfo = u32;
pub const StdVideoEncodeH265SliceSegmentHeaderFlags = u32; pub const StdVideoEncodeH265SliceSegmentHeader = u32;
pub const StdVideoEncodeH265ReferenceInfoFlags = u32; pub const StdVideoEncodeH265ReferenceInfo = u32;
pub const StdVideoEncodeH265ReferenceModificationFlags = u32; pub const StdVideoEncodeH265ReferenceListsInfo = u32;
pub const StdVideoEncodeAV1OperatingPointInfo = u32; pub const StdVideoEncodeH265SliceSegmentHeaderFlags = u32;
pub const StdVideoEncodeH265ReferenceInfoFlags = u32;
pub const StdVideoEncodeH265ReferenceModificationFlags = u32;
pub const StdVideoEncodeAV1OperatingPointInfo = u32;
} else struct {};
comptime { comptime {
@setEvalBranchQuota(1000000); @setEvalBranchQuota(1000000);